|
|
1.1 ! root 1: \input nwmac ! 2: \filename{mipsglue.nw} ! 3: \begindocs{0} ! 4: \enddocs ! 5: \begindocs{1} ! 6: For the Mips, all comments are no-ops, so to get diagnostics in ! 7: assembly mode we have to slip in and define a new comment function. ! 8: Our life is further complicated by the fact that the stream on which ! 9: comments are to be written is bound late, so we have to save up comments ! 10: and then write them when asked to \code{}generate\edoc{}. ! 11: \enddocs ! 12: \begincode{2} ! 13: \moddef{*}\endmoddef ! 14: structure MipsAC : ASSEMBLER = struct ! 15: val diag_out = ref std_out ! 16: structure MCN = struct ! 17: open MipsCoder ! 18: structure M = struct ! 19: open M ! 20: fun comment s = output (!diag_out) s ! 21: end ! 22: end ! 23: ! 24: structure CM = MipsCM(MCN) ! 25: ! 26: structure Gen = CPScomp(CM) ! 27: fun generate (lexp, stream) = ( ! 28: diag_out := stream; ! 29: Gen.compile lexp; ! 30: MipsCoder.codestats stream; ! 31: Emitters.address := 0; ! 32: MipsCoder.codegen (Emitters.MipsAsm stream); ! 33: ()) ! 34: end ! 35: ! 36: \endcode ! 37: \begincode{3} ! 38: \moddef{*}\endmoddef ! 39: structure MipsCodeStats : ASSEMBLER = struct ! 40: val diag_out = ref std_out ! 41: structure MCN = MipsCoder ! 42: ! 43: structure CM = MipsCM(MCN) ! 44: ! 45: structure Gen = CPScomp(CM) ! 46: fun generate (lexp, stream) = ( ! 47: Gen.compile lexp; ! 48: MipsCoder.codestats stream; ! 49: ()) ! 50: end ! 51: ! 52: \endcode ! 53: \begindocs{4} ! 54: Mips machines come in two byte-orders, so we need two of ! 55: every machinelike thing. ! 56: \enddocs ! 57: \begincode{5} ! 58: \moddef{*}\endmoddef ! 59: structure MipsMCBig : CODEGENERATOR = struct ! 60: structure CM = MipsCM(MipsCoder) ! 61: structure Gen = CPScomp(CM) ! 62: ! 63: fun generate lexp = ( ! 64: Gen.compile lexp; ! 65: MipsCoder.codegen (Emitters.BigEndian); ! 66: Emitters.emitted_string () ! 67: ) ! 68: end ! 69: ! 70: structure MipsMCLittle : CODEGENERATOR = struct ! 71: structure CM = MipsCM(MipsCoder) ! 72: structure Gen = CPScomp(CM) ! 73: fun diag (s : string) f x = ! 74: f x handle e => ! 75: (print "?exception "; print (System.exn_name e); ! 76: print " in mipsglue."; print s; print "\\n"; ! 77: raise e) ! 78: ! 79: fun generate lexp = ( ! 80: diag "Gen.compile" Gen.compile lexp; ! 81: diag "MipsCoder.codegen" MipsCoder.codegen (Emitters.LittleEndian); ! 82: diag "Emitters.emitted_string" Emitters.emitted_string () ! 83: ) ! 84: end ! 85: ! 86: ! 87: structure CompMipsLittle = Batch(structure M=MipsMCLittle and A=MipsAC) ! 88: structure IntMipsLittle = IntShare(MipsMCLittle) ! 89: ! 90: structure CompMipsBig = Batch(structure M=MipsMCBig and A=MipsAC) ! 91: structure IntMipsBig = IntShare(MipsMCBig) ! 92: ! 93: structure CompMipsStats = Batch(structure M=MipsMCLittle and A=MipsCodeStats) ! 94: \endcode ! 95: \filename{emitters.nw} ! 96: \begindocs{0} ! 97: \section{Emitters} ! 98: We have an odd problem---we need to be able to emit either a 32-bit ! 99: integer or a string. ! 100: The order in which the bytes of the integer are emitted depends on ! 101: whether the target machine is BigEndian or LittleEndian, but the ! 102: bytes of the string should be emitted in the same order on both machines. ! 103: This means that the two emission functions depend on each other, but ! 104: in a machine-dependent way, so we bundle them up. ! 105: We also have to be able to emit two words for floating point constants. ! 106: The way to do this can be derived from \code{}emit_word\edoc{}, and this ! 107: code seems to be the sensible place to do that. ! 108: So we define a type \code{}emitter_triple\edoc{} ! 109: and pass them around that way. ! 110: ! 111: \enddocs ! 112: \begindocs{1} ! 113: Eventually we want to take all the words and strings that have been ! 114: emitted and bundle them up into a single string using \code{}implode\edoc{}. ! 115: We'll take the following tack with that: ! 116: each emitter will squirrel some info away in a reference variable. ! 117: A function \code{}emitted_string: unit -> string\edoc{} will take the ! 118: squirreled information and return a string that represents ! 119: everything emitted so far. ! 120: As a side effect, it will reset the emitter system to its initial ! 121: state, where ``everything emitted so far'' is the empty string. ! 122: ! 123: The actual implementation will be a list of strings which is reversed ! 124: and imploded. ! 125: \enddocs ! 126: \begincode{2} ! 127: \moddef{signature}\endmoddef ! 128: signature EMITTERS = sig ! 129: type emitter_triple ! 130: val LittleEndian : emitter_triple ! 131: val BigEndian : emitter_triple ! 132: val emitted_string : unit -> string ! 133: val MipsAsm : outstream -> emitter_triple ! 134: val address : int ref ! 135: end ! 136: ! 137: \endcode ! 138: \begindocs{3} ! 139: First something that's capable of emitting real code, then ! 140: something that can print assembly code. ! 141: We emit the assembly code to output right away, without any fooling. ! 142: \enddocs ! 143: \begincode{4} ! 144: \moddef{*}\endmoddef ! 145: structure Emitters : EMITTERS = struct ! 146: type emitter_triple = (int * int -> unit) * (int -> string -> unit) ! 147: * (string -> unit) ! 148: local ! 149: \LA{}memory and basic services\RA{} ! 150: in ! 151: \LA{}string emitter\RA{} ! 152: \LA{}little-endian emitter\RA{} ! 153: \LA{}big-endian emitter\RA{} ! 154: fun emitted_string () = ! 155: let val s = implode (rev (!so_far)) ! 156: in so_far := nil; s ! 157: end ! 158: end ! 159: structure BigReal = MipsReal(struct val emit_word = emit_pair_big end) ! 160: structure LittleReal =MipsReal(struct val emit_word = emit_pair_little end) ! 161: val LittleEndian = (emit_pair_little,emit_string,LittleReal.realconst) ! 162: val BigEndian = (emit_pair_big,emit_string,BigReal.realconst) ! 163: \LA{}assembly-code emitters\RA{} ! 164: end ! 165: ! 166: ! 167: \endcode ! 168: \begindocs{5} ! 169: Here is a variable to remember what's been emitted so far ! 170: \enddocs ! 171: \begincode{6} ! 172: \moddef{memory and basic services}\endmoddef ! 173: val so_far = ref nil : string list ref ! 174: fun squirrel s = so_far := s :: !so_far ! 175: fun emit_byte n = squirrel (chr n) ! 176: \endcode ! 177: \begincode{7} ! 178: \moddef{string emitter}\endmoddef ! 179: fun emit_string n s = squirrel (substring(s,0,n)) ! 180: handle e => ! 181: (print "?exception "; print (System.exn_name e); ! 182: print (" in emitters.emit_string "^ ! 183: (Integer.makestring n) ^ " \\""^s^"\\"\\n"); ! 184: raise e) ! 185: ! 186: \endcode ! 187: \begindocs{8} ! 188: Little-endian means the little (least significant) end first, ! 189: like the VAX. ! 190: We parameterize the real emitters by a function that emits a byte. ! 191: \enddocs ! 192: \begincode{9} ! 193: \moddef{little-endian emitter}\endmoddef ! 194: fun emit_pair_little(hi,lo) = ! 195: let open Bits ! 196: fun emit_word(n) = ! 197: (emit_byte(andb(n,255));emit_byte(andb(rshift(n,8),255))) ! 198: in (emit_word(lo);emit_word(hi)) ! 199: end ! 200: ! 201: \endcode ! 202: \begincode{10} ! 203: \moddef{big-endian emitter}\endmoddef ! 204: fun emit_pair_big(hi,lo) = ! 205: let open Bits ! 206: fun emit_word(n) = ! 207: (emit_byte(andb(rshift(n,8),255));emit_byte(andb(n,255))) ! 208: in (emit_word(hi);emit_word(lo)) ! 209: end ! 210: ! 211: ! 212: \endcode ! 213: \begindocs{11} ! 214: Now the assembly code. ! 215: to make it easier to debug, we print out addresses in the same format ! 216: as {\tt dbx}: we use the byte address and we print it in hex. ! 217: ! 218: We have to bend over backwards to handle real numbers ! 219: ! 220: \enddocs ! 221: \begincode{12} ! 222: \moddef{assembly-code emitters}\endmoddef ! 223: val address = ref 0 (* address of next instruction in words *) ! 224: \LA{}real number state info and \code{}decode_real_ptr\edoc{}\RA{} ! 225: fun MipsAsm stream = ! 226: let fun say s = (output stream s; flush_out stream) ! 227: fun printaddr addrref = ! 228: let val n = !addrref ! 229: in (if n<10 then " " else if n < 100 then " " else "") ! 230: ^ (Integer.makestring n) ! 231: end ! 232: local ! 233: open Bits ! 234: fun hexdigit n = ! 235: let val d = andb(n,15) ! 236: in if d <= 9 then chr(d+ord("0")) ! 237: else chr(d-10+ord("a")) ! 238: end ! 239: fun hex1 n = hexdigit(rshift(n,4))^hexdigit(n) ! 240: fun hex2 n = hex1(rshift(n,8))^hex1(n) ! 241: fun hex4 n = hex2(rshift(n,16))^hex2(n) ! 242: in ! 243: fun hex(hi,lo) = hex2(hi) ^ hex2(lo) ! 244: fun printaddr addrref = ! 245: let val n = 4 * (!addrref) (* address in bytes *) ! 246: in "0x" ^ (hex4 n) ! 247: end ! 248: end ! 249: fun decode x = ( ! 250: say ((printaddr address) ^ ": (" ^ (hex x) ^") " ! 251: ^ (MipsDecode.decode x)); ! 252: address := !address + 1; () ! 253: ) ! 254: fun do_decode_real(w,s) = ( ! 255: say ((printaddr address) ^ ": (" ^ (hex w) ^") " ! 256: ^ s ^ "\\n"); ! 257: address := !address + 1; () ! 258: ) ! 259: fun decode_real s = (real_string := s; AsmReal.realconst s) ! 260: fun decode_string n s = ! 261: if n > 0 then ! 262: (say ((printaddr address) ! 263: ^ ": \\"" ^substring(s,0,4) ^"\\"\\n"); ! 264: address := !address + 1; ! 265: decode_string (n-4) (substring(s,4,String.length(s)-4)) ! 266: ) ! 267: else () ! 268: in ! 269: decode_real_ptr := SOME do_decode_real; ! 270: (decode,decode_string,decode_real) : emitter_triple ! 271: end ! 272: \endcode ! 273: \begincode{13} ! 274: \moddef{real number state info and \code{}decode_real_ptr\edoc{}}\endmoddef ! 275: val decode_real_ptr = ref NONE : ((int * int) * string -> unit) option ref ! 276: (* used to emit asm code for a real word *) ! 277: ! 278: val real_least = ref NONE : (int * int) option ref ! 279: (* least significant word of real *) ! 280: val real_string = ref "" ! 281: fun emit_real_word w = ! 282: let val decode_real = case !decode_real_ptr of ! 283: SOME f => f ! 284: | NONE => ErrorMsg.impossible "missed real decoder in mips asm" ! 285: in ! 286: case !real_least of ! 287: NONE => real_least := SOME w ! 288: | SOME least => ! 289: (decode_real(least,"[low word of "^(!real_string)^"]"); ! 290: decode_real(w,"[high word of "^(!real_string)^"]")) ! 291: end ! 292: ! 293: structure AsmReal = MipsReal(struct val emit_word = emit_real_word end) ! 294: ! 295: \endcode ! 296: \filename{mipsreal.nw} ! 297: \begindocs{0} ! 298: \subsection{Handling IEEE floating point constants} ! 299: Here we take care of converting floating point constants from ! 300: string representation to 64-bit IEEE representation. ! 301: We use the machinery developed for the Sparc by John Reppy. ! 302: ! 303: Reppy's functor accepts a simple structure with a single value, ! 304: \code{}emitWord : int -> unit\edoc{}, which emits a 16-bit word. ! 305: It produces a \code{}PRIMREAL\edoc{}. ! 306: When \code{}RealConst\edoc{} is applied to the result, it produces a ! 307: structure containing a single function, \code{}val realconst : string -> unit\edoc{}. ! 308: This function, when applied to a string, emits the four sixteen-bit words ! 309: of the IEEE representation, most significant first. ! 310: ! 311: Our job will be to convert this to something that emits the two 32-bit ! 312: words of the constant, least significant word first. ! 313: First, let's consider the state information that has to be retained ! 314: while the halfwords are being emitted, and functions that change that state. ! 315: \enddocs ! 316: \begincode{1} ! 317: \moddef{state info}\endmoddef ! 318: val halfwords = ref nil : int list ref (* halfwords already out *) ! 319: val count = ref 0 (* length of halfwords *) ! 320: fun reset_state () = (halfwords := nil; count := 0) ! 321: fun add_half h = (count := !count + 1; halfwords := h :: (!halfwords)) ! 322: ! 323: \endcode ! 324: \begincode{2} ! 325: \moddef{emitting a halfword}\endmoddef ! 326: fun emit_half h = ! 327: if !count = 3 then (emit_four (h::(!halfwords)); reset_state()) ! 328: else add_half h ! 329: ! 330: \endcode ! 331: \begindocs{3} ! 332: To emit the whole list, we have to emit the words, one at a time. ! 333: We use descriptive names to remind ourselves what is signficant ! 334: (highest is most significant). ! 335: \enddocs ! 336: \begincode{4} ! 337: \moddef{emitting four halfwords}\endmoddef ! 338: fun emit_four [lowest,low,high,highest] = ! 339: (emit_word(low,lowest);emit_word(highest,high)) ! 340: | emit_four _ = ErrorMsg.impossible "bad floating pt constant in mips" ! 341: ! 342: \endcode ! 343: \begindocs{5} ! 344: Now, we bundle up the whole thing in a functor that ! 345: gets passed a structure holding \code{}emit_word\edoc{} and returns ! 346: one containing \code{}realconst\edoc{}. ! 347: \enddocs ! 348: \begincode{6} ! 349: \moddef{*}\endmoddef ! 350: functor MipsReal(E: sig val emit_word : int * int -> unit end) : REALCONST = ! 351: struct ! 352: open E ! 353: \LA{}state info\RA{} ! 354: \LA{}emitting four halfwords\RA{} ! 355: \LA{}emitting a halfword\RA{} ! 356: structure IEEERealConst = ! 357: RealConst(IEEEReal(struct val emitWord = emit_half end)) ! 358: val realconst = IEEERealConst.realconst ! 359: end ! 360: ! 361: ! 362: ! 363: ! 364: \endcode ! 365: \filename{mips.nw} ! 366: \begindocs{0} ! 367: \section{Using \code{}MIPSCODER\edoc{} to implement a \code{}CMACHINE\edoc{}} ! 368: ! 369: \enddocs ! 370: \begincode{1} ! 371: \moddef{*}\endmoddef ! 372: functor MipsCM(MipsC : MIPSCODER) : CMACHINE = struct ! 373: ! 374: open MipsC System.Tags ! 375: ! 376: \LA{}utility functions\RA{} ! 377: ! 378: \LA{}immediate and register functions\RA{} ! 379: ! 380: \LA{}register definitions\RA{} ! 381: ! 382: \LA{}move\RA{} ! 383: \LA{}alignment, marks, and constants\RA{} ! 384: \LA{}labels\RA{} ! 385: \LA{}record manipulation\RA{} ! 386: \LA{}indexed fetch and store (byte)\RA{} ! 387: \LA{}indexed fetch and store (word)\RA{} ! 388: \LA{}arithmetic\RA{} ! 389: \LA{}shifts\RA{} ! 390: \LA{}arithmetic and shifts with overflow detection\RA{} ! 391: \LA{}bitwise operations\RA{} ! 392: \LA{}branches\RA{} ! 393: ! 394: \LA{}floating point\RA{} ! 395: ! 396: \LA{}memory check\RA{} ! 397: ! 398: \LA{}omitted functions\RA{} ! 399: ! 400: val comment = M.comment ! 401: ! 402: (* +DEBUG *) ! 403: \LA{}DEBUG code\RA{} ! 404: (* -DEBUG *) ! 405: ! 406: end (* MipsCM *) ! 407: ! 408: \endcode ! 409: \begindocs{2} ! 410: The debugging code replaces possibly offensive functions with functions ! 411: that diagnose their own exceptions. ! 412: \enddocs ! 413: \begincode{3} ! 414: \moddef{DEBUG code}\endmoddef ! 415: fun diag (s : string) f x = ! 416: f x handle e => ! 417: (print "?exception "; print (System.exn_name e); ! 418: print " in mips."; print s; print "\\n"; ! 419: raise e) ! 420: ! 421: \endcode ! 422: \begincode{4} ! 423: \moddef{immediate and register functions}\endmoddef ! 424: val immed = Immed ! 425: fun isimmed(Immed i) = SOME i ! 426: | isimmed _ = NONE ! 427: ! 428: fun isreg(Direct(Reg i)) = SOME i | isreg _ = NONE ! 429: fun eqreg (a: EA) b = a=b ! 430: ! 431: ! 432: \endcode ! 433: \begindocs{5} ! 434: Here's what our register conventions are: ! 435: \input regs ! 436: \enddocs ! 437: \begincode{6} ! 438: \moddef{register definitions}\endmoddef ! 439: val standardarg = Direct(Reg 2) ! 440: val standardcont = Direct(Reg 3) ! 441: val standardclosure = Direct(Reg 4) ! 442: val miscregs = map (Direct o Reg) [5,6,7,8,9,10,11,12,13,14, ! 443: 15,16,17,18,19] ! 444: val storeptr as Direct storeptr' = Direct(Reg 22) ! 445: val dataptr as Direct dataptr' = Direct(Reg 23) ! 446: val exnptr = Direct(Reg 30) ! 447: ! 448: (* internal use only *) ! 449: val my_arithtemp as Direct my_arithtemp'= Direct(Reg 20) ! 450: val my_ptrtemp as Direct my_ptrtemp' = Direct(Reg 21) ! 451: ! 452: (* exported for external use *) ! 453: val arithtemp as Direct arithtemp' = Direct(Reg 24) ! 454: val arithtemp2 as Direct arithtemp2'= Direct(Reg 25) ! 455: ! 456: \endcode ! 457: \begincode{7} ! 458: \moddef{move}\endmoddef ! 459: fun move (src,Direct dest) = M.move(src, dest) ! 460: | move _ = ErrorMsg.impossible "destination of move not register in mips" ! 461: \endcode ! 462: \begincode{8} ! 463: \moddef{alignment, marks, and constants}\endmoddef ! 464: val align = M.align ! 465: val mark = M.mark ! 466: ! 467: val emitlong = M.emitlong ! 468: val realconst = M.realconst ! 469: val emitstring = M.emitstring ! 470: ! 471: \endcode ! 472: \begincode{9} ! 473: \moddef{labels}\endmoddef ! 474: fun emitlab(i,Immedlab lab) = M.emitlab(i,lab) ! 475: | emitlab _ = ErrorMsg.impossible "bad emitlab arg in mips" ! 476: fun newlabel() = Immedlab(M.newlabel()) ! 477: fun define (Immedlab lab) = M.define lab ! 478: | define _ = ErrorMsg.impossible "bad define arg in mips" ! 479: \endcode ! 480: \begincode{10} ! 481: \moddef{DEBUG code}\endmoddef ! 482: val emitlab = diag "emitlab" emitlab ! 483: val define = diag "define" define ! 484: ! 485: ! 486: \endcode ! 487: \begindocs{11} ! 488: We only ever put the address of a newly created record into a register. ! 489: If I make this out correctly, the first word on the list of ! 490: values \code{}vl\edoc{} is actually a descriptor. ! 491: BUGS: The original routine put the address of the descriptor ! 492: into \code{}z\edoc{}. ! 493: What needs to go into \code{}z\edoc{} is the address of the first word in the record. ! 494: We can get this by adding 4 to the \code{}dataptr'\edoc{}. ! 495: \enddocs ! 496: \begincode{12} ! 497: \moddef{record manipulation}\endmoddef ! 498: fun record(vl, Direct z) = ! 499: let open CPS ! 500: val len = List.length vl ! 501: fun f(i,nil) = () ! 502: | f(i,(r, SELp(j,p))::rest) = (* follow ptrs to get the item *) ! 503: (M.lw(my_ptrtemp', r, j*4); f(i,(my_ptrtemp,p)::rest)) ! 504: | f(i,(Direct r,OFFp 0)::rest) = (* simple store, last first *) ! 505: (M.sw(r, dataptr, i*4); f(i-1,rest)) ! 506: | f(i,(Direct r, OFFp j)::rest) = ! 507: (M.add(r, Immed(4*j), my_ptrtemp'); ! 508: f(i,(my_ptrtemp,OFFp 0)::rest)) ! 509: | f(i,(ea,p)::rest) = (* convert to register-based *) ! 510: (M.move(ea, my_ptrtemp'); f(i,(my_ptrtemp,p)::rest)) ! 511: in f(len - 1, rev vl); (* store first word in \code{}0(dataptr')\edoc{} *) ! 512: M.add(dataptr', Immed 4, z); ! 513: M.add(dataptr', Immed(4*len), dataptr') ! 514: end ! 515: | record _ = ErrorMsg.impossible "result of record not register in mips" ! 516: ! 517: fun select(i, r, Direct s) = M.lw(s, r, i*4) ! 518: | select _ = ErrorMsg.impossible "result of select not register in mips" ! 519: ! 520: fun offset(i, Direct r, Direct s) = M.add(r,Immed(i*4), s) ! 521: | offset _ = ErrorMsg.impossible "nonregister arg to offset in mips" ! 522: \endcode ! 523: \begincode{13} ! 524: \moddef{DEBUG code}\endmoddef ! 525: val record = diag "record" record ! 526: val select = diag "select" select ! 527: val offset = diag "offset" offset ! 528: ! 529: \endcode ! 530: \begindocs{14} ! 531: For the indexed fetch and store, arithtemp is {\em not} tagged---the ! 532: tags are removed at a higher level (in {\tt generic.sml}). ! 533: These could be made faster for the case when they're called with immediate ! 534: constants as \code{}x\edoc{}. ! 535: \enddocs ! 536: \begincode{15} ! 537: \moddef{indexed fetch and store (byte)}\endmoddef ! 538: (* fetchindexb(x,y) fetches a byte: y <- mem[x+arithtemp] ! 539: y cannot be arithtemp *) ! 540: fun fetchindexb(x,Direct y) = ! 541: (M.add(arithtemp',x,my_arithtemp'); ! 542: M.lbu(y,my_arithtemp,0)) ! 543: | fetchindexb _ = ErrorMsg.impossible "fetchb result not register in mips" ! 544: ! 545: (* storeindexb(x,y) stores a byte: mem[y+arithtemp] <- x; *) ! 546: fun storeindexb(Direct x,y) = ! 547: (M.add(arithtemp',y,my_arithtemp'); ! 548: M.sb(x,my_arithtemp,0)) ! 549: | storeindexb _ = ErrorMsg.impossible "storeb arg not register in mips" ! 550: ! 551: (* jmpindexb(x) pc <- (x+arithtemp) *) ! 552: fun jmpindexb x = (M.add(arithtemp',x,my_arithtemp'); ! 553: M.jump(my_arithtemp')) ! 554: ! 555: \endcode ! 556: \begincode{16} ! 557: \moddef{DEBUG code}\endmoddef ! 558: val fetchindexb = diag "fetchindexb" fetchindexb ! 559: val storeindexb = diag "storeindexb" storeindexb ! 560: val jmpindexb = diag "jmpindexb" jmpindexb ! 561: ! 562: ! 563: \endcode ! 564: \begindocs{17} ! 565: Here it looks like \code{}z\edoc{} is a tagged integer number of words, ! 566: so that \code{}2*(z-1)\edoc{} converts to the appropriate byte offset. ! 567: But I'm just guessing. ! 568: In any case, it saves an instruction to compute \code{}2*z\edoc{} (actually \code{}z+z\edoc{}) ! 569: and ! 570: load (or store) with offset \code{}~2\edoc{}. ! 571: ! 572: Anything stored with \code{}storeindexl\edoc{} is being put into an array, so it ! 573: is safe to treat it as a pointer. ! 574: \enddocs ! 575: \begincode{18} ! 576: \moddef{indexed fetch and store (word)}\endmoddef ! 577: (* fetchindexl(x,y,z) fetches a word: y <- mem[x+2*(z-1)] *) ! 578: (* storeindexl(x,y,z) stores a word: mem[y+2*(z-1)] <- x *) ! 579: ! 580: fun fetchindexl(x,Direct y, Direct z) = ! 581: (M.sll(Immed 1,z,my_arithtemp'); ! 582: M.add(my_arithtemp',x,my_arithtemp'); ! 583: M.lw(y, my_arithtemp,~2)) ! 584: | fetchindexl(x,Direct y, Immed z) = M.lw(y, x, z+z-2) ! 585: | fetchindexl _ = ErrorMsg.impossible "fetchl result not register in mips" ! 586: ! 587: fun storeindexl(Direct x,y, Immed 1) = M.sw(x,y,0) ! 588: | storeindexl(Direct x,y,Direct z) = ! 589: (M.sll(Immed 1,z,my_arithtemp'); ! 590: M.add(my_arithtemp',y,my_arithtemp'); ! 591: M.sw(x, my_arithtemp,~2)) ! 592: | storeindexl(Direct x,y,Immed z) = M.sw(x,y,z+z-2) ! 593: ! 594: | storeindexl(Direct _,_,Immedlab _) = ! 595: ErrorMsg.impossible "storeindexl(Direct _,_,Immedlab _) in mips" ! 596: ! 597: | storeindexl(Immedlab label,y,z) = ! 598: (M.move(Immedlab label,my_ptrtemp'); ! 599: storeindexl(my_ptrtemp,y,z)) ! 600: ! 601: | storeindexl(Immed constant,y,offset) = ! 602: (M.move(Immed constant,my_ptrtemp'); ! 603: storeindexl(my_ptrtemp,y,offset)) ! 604: ! 605: \endcode ! 606: \begincode{19} ! 607: \moddef{DEBUG code}\endmoddef ! 608: val fetchindexl = diag "fetchindexl" fetchindexl ! 609: val storeindexl = diag "storeindexl" storeindexl ! 610: ! 611: ! 612: \endcode ! 613: \begindocs{20} ! 614: The function \code{}three\edoc{} makes commutative three-operand ! 615: instructions easier to call. ! 616: All three operands become \code{}EA\edoc{}s, and it is enough if either of the ! 617: first two operands is a register. ! 618: \enddocs ! 619: \begincode{21} ! 620: \moddef{utility functions}\endmoddef ! 621: fun three f (Direct x, ea, Direct y) = f(x,ea,y) ! 622: | three f (ea, Direct x, Direct y) = f(x,ea,y) ! 623: | three f _ =ErrorMsg.impossible "neither arg to three f is register in mips" ! 624: ! 625: \endcode ! 626: \begindocs{22} ! 627: I assume that shifts are only ever done on arithmetic quantities, ! 628: not pointers, so that I am justified in using \code{}my_arithtemp'\edoc{} to ! 629: store intermediate values. This is consistent with being unwilling ! 630: to shift things matching \code{}Immedlab _\edoc{}. ! 631: Appel agrees that pointers aren't shifted, as far as he can remember. ! 632: \enddocs ! 633: \begincode{23} ! 634: \moddef{shifts}\endmoddef ! 635: fun ashr(shamt, Direct op1, Direct result) = M.sra(shamt,op1,result) ! 636: | ashr(shamt, Immed op1, Direct result) = ! 637: (M.move(Immed op1,my_arithtemp'); M.sra(shamt,my_arithtemp',result)) ! 638: | ashr _ = ErrorMsg.impossible "ashr args don't match in mips" ! 639: fun ashl(shamt, Direct op1, Direct result) = M.sll(shamt,op1,result) ! 640: | ashl(shamt, Immed op1, Direct result) = ! 641: (M.move(Immed op1,my_arithtemp'); M.sll(shamt,my_arithtemp',result)) ! 642: | ashl _ = ErrorMsg.impossible "ashl args don't match in mips" ! 643: \endcode ! 644: \begincode{24} ! 645: \moddef{DEBUG code}\endmoddef ! 646: val ashr = diag "ashr" ashr ! 647: val ashl = diag "ashl" ashl ! 648: ! 649: \endcode ! 650: \begincode{25} ! 651: \moddef{bitwise operations}\endmoddef ! 652: val orb = three M.or ! 653: val andb = three M.and' ! 654: fun notb (a,b) = subl3(a, Immed ~1, b) (* ~1 - a == one's complement *) ! 655: val xorb = three M.xor ! 656: \endcode ! 657: \begincode{26} ! 658: \moddef{DEBUG code}\endmoddef ! 659: val orb = diag "orb" orb ! 660: val andb = diag "andb" andb ! 661: val notb = diag "notb" notb ! 662: val xorb = diag "xorb" xorb ! 663: ! 664: ! 665: \endcode ! 666: \begindocs{27} ! 667: Subtraction may appear a bit odd. ! 668: The MIPS machine instruction and \code{}MIPSCODER.sub\edoc{} both subtract ! 669: their second operand from their first operand. ! 670: The VAX machine instruction and \code{}CMACHINE.subl3\edoc{} both subtract ! 671: their first operand from their second operand. ! 672: This will certainly lead to endless confusion. ! 673: \enddocs ! 674: \begincode{28} ! 675: \moddef{arithmetic}\endmoddef ! 676: val addl3 = three M.add ! 677: ! 678: fun subl3(Immed k, x, y) = addl3(x, Immed(~k), y) ! 679: | subl3(Direct x, Direct y, Direct z) = M.sub(y,x,z) ! 680: | subl3(x, Immed k, dest) = ! 681: (M.move(Immed k, my_arithtemp'); ! 682: subl3(x, my_arithtemp, dest)) ! 683: | subl3 _ = ErrorMsg.impossible "subl3 args don't match in mips" ! 684: ! 685: \endcode ! 686: \begindocs{29} ! 687: We assume that any quantities being multiplied are arithmetic ! 688: quantities, not pointers. ! 689: \enddocs ! 690: \begincode{30} ! 691: \moddef{arithmetic}\endmoddef ! 692: fun mull2(Direct x, Direct y) = M.mult(y,x,y) ! 693: | mull2(Immed x, Direct y) = (M.move(Immed x,my_arithtemp'); ! 694: M.mult(y,my_arithtemp',y)) ! 695: | mull2 _ = ErrorMsg.impossible "mull2 args don't match in mips" ! 696: fun divl2(Direct x, Direct y) = M.div(y,x,y) ! 697: | divl2(Immed x, Direct y) = (M.move(Immed x,my_arithtemp'); ! 698: M.div(y,my_arithtemp',y)) ! 699: | divl2 _ = ErrorMsg.impossible "divl2 args don't match in mips" ! 700: ! 701: \endcode ! 702: \begincode{31} ! 703: \moddef{DEBUG code}\endmoddef ! 704: val addl3 = diag "addl3" addl3 ! 705: val subl3 = diag "subl3" subl3 ! 706: val mull2 = diag "mull2" mull2 ! 707: val divl2 = diag "divl2" divl2 ! 708: ! 709: ! 710: \endcode ! 711: \begindocs{32} ! 712: The Mips hardware detects two's complement integer overflow on ! 713: add and subtract instructions only. ! 714: The exception is not maskable (see the Mips book, page 5-18). ! 715: At the moment we don't implement any overflow detection for multiplications ! 716: or for left shifts. ! 717: This has consequences only for coping with real constants and for ! 718: compiling user programs. ! 719: \enddocs ! 720: \begincode{33} ! 721: \moddef{arithmetic and shifts with overflow detection}\endmoddef ! 722: val addl3t = addl3 ! 723: val subl3t = subl3 ! 724: \endcode ! 725: \begindocs{34} ! 726: The Mips multiplies two 32-bit quantities to get a 64-bit result. ! 727: That result fits in 32 bits if and only if the high-order word is zero or ! 728: negative one, and it has the same sign as the low order word. ! 729: Thus, we can add the sign bit of the low order word to the high order ! 730: word, and we have overflow if and only if the result is nonzero. ! 731: \enddocs ! 732: \begincode{35} ! 733: \moddef{arithmetic and shifts with overflow detection}\endmoddef ! 734: fun mull2t(x,y as Direct y') = ! 735: let val ok = M.newlabel() ! 736: in mull2(x,y); ! 737: M.mfhi(my_arithtemp'); ! 738: M.slt(y',Direct (Reg 0),my_ptrtemp'); (* 0 or 1 OK in pointer *) ! 739: M.add(my_arithtemp',my_ptrtemp,my_arithtemp'); ! 740: M.beq(true,my_arithtemp',Reg 0,ok); (* OK if not overflow *) ! 741: M.lui(my_arithtemp',32767); ! 742: M.add(my_arithtemp',my_arithtemp,my_arithtemp'); (* overflows *) ! 743: M.define(ok) ! 744: end ! 745: | mull2t _ = ErrorMsg.impossible "result of mull2t not register in mips" ! 746: ! 747: \endcode ! 748: \begincode{36} ! 749: \moddef{DEBUG code}\endmoddef ! 750: val addl3t = diag "addl3t" addl3t ! 751: val subl3t = diag "subl3t" subl3t ! 752: val mull2t = diag "mull2t" mull2t ! 753: val ashlt = diag "ashlt" ashlt ! 754: ! 755: ! 756: \endcode ! 757: \begindocs{37} ! 758: We hack \code{}ibranch\edoc{} to make sure it will only reverse once. ! 759: It's easier than thinking. ! 760: \enddocs ! 761: \begincode{38} ! 762: \moddef{branches}\endmoddef ! 763: datatype condition = NEQ | EQL | LEQ | GEQ | LSS | GTR ! 764: local ! 765: fun makeibranch reverse = ! 766: let ! 767: fun ibranch (cond, Immed a, Immed b, Immedlab label) = ! 768: if (case cond of EQL => a=b | NEQ => a<>b | LSS => a<b | ! 769: LEQ => a<=b | GTR => a>b | GEQ => a>=b) ! 770: then M.beq(true,Reg 0, Reg 0, label) else () ! 771: | ibranch (NEQ, Direct r, Direct s, Immedlab label) = ! 772: M.beq(false, r, s, label) ! 773: | ibranch (NEQ, Direct r, x, Immedlab label) = ! 774: (M.move(x, my_arithtemp'); ! 775: M.beq(false, r, my_arithtemp', label)) ! 776: | ibranch (EQL, Direct r, Direct s, Immedlab label) = ! 777: M.beq(true, r, s, label) ! 778: | ibranch (EQL, Direct r, x, Immedlab label) = ! 779: (M.move(x, my_arithtemp'); ! 780: M.beq(true, r, my_arithtemp', label)) ! 781: | ibranch (LSS, Direct r, x, Immedlab lab) = ! 782: (M.slt(r,x,my_arithtemp'); ! 783: M.beq(false,Reg 0, my_arithtemp',lab)) ! 784: | ibranch (GEQ, Direct r, x, Immedlab lab) = ! 785: (M.slt(r,x,my_arithtemp'); ! 786: M.beq(true,Reg 0, my_arithtemp',lab)) ! 787: | ibranch (GTR, x, Direct r, Immedlab lab) = ! 788: (M.slt(r,x,my_arithtemp'); ! 789: M.beq(false,Reg 0, my_arithtemp',lab)) ! 790: | ibranch (LEQ, x, Direct r, Immedlab lab) = ! 791: (M.slt(r,x,my_arithtemp'); ! 792: M.beq(true,Reg 0, my_arithtemp',lab)) ! 793: (* These two cases added to prevent infinite reversal *) ! 794: | ibranch (GTR, Direct r, x, Immedlab lab) = ! 795: (M.move(x, my_arithtemp'); ! 796: M.slt(my_arithtemp',Direct r,my_arithtemp'); ! 797: M.beq(false,Reg 0,my_arithtemp',lab)) ! 798: | ibranch (LEQ, Direct r, x, Immedlab lab) = ! 799: (M.move(x, my_arithtemp'); ! 800: M.slt(my_arithtemp',Direct r,my_arithtemp'); ! 801: M.beq(true,Reg 0,my_arithtemp',lab)) ! 802: | ibranch (_, Immedlab _, Immedlab _, _) = ! 803: ErrorMsg.impossible "bad ibranch args 1 in mips" ! 804: | ibranch (_, Immedlab _, _, _) = ! 805: ErrorMsg.impossible "bad ibranch args 1a in mips" ! 806: | ibranch (_, _, Immedlab _, _) = ! 807: ErrorMsg.impossible "bad ibranch args 1b in mips" ! 808: | ibranch (_, _, _, Direct _) = ! 809: ErrorMsg.impossible "bad ibranch args 2 in mips" ! 810: | ibranch (_, _, _, Immed _) = ! 811: ErrorMsg.impossible "bad ibranch args 3 in mips" ! 812: | ibranch (cond, x, y, l) = ! 813: let fun rev LEQ = GEQ ! 814: | rev GEQ = LEQ ! 815: | rev LSS = GTR ! 816: | rev GTR = LSS ! 817: | rev NEQ = NEQ ! 818: | rev EQL = EQL ! 819: in if reverse then (makeibranch false) (rev cond, y,x,l) ! 820: else ErrorMsg.impossible "infinite ibranch reversal in mips" ! 821: ! 822: end ! 823: in ibranch ! 824: end ! 825: in ! 826: val ibranch = makeibranch true ! 827: end ! 828: ! 829: \endcode ! 830: \begincode{39} ! 831: \moddef{branches}\endmoddef ! 832: fun jmp (Direct r) = M.jump(r) ! 833: | jmp (Immedlab lab) = M.beq(true,Reg 0,Reg 0,lab) ! 834: | jmp (Immed i) = ErrorMsg.impossible "jmp (Immed i) in mips" ! 835: ! 836: ! 837: (* branch on bit set *) ! 838: fun bbs (Immed k, Direct y, Immedlab label) = ! 839: (M.and'(y,Immed (Bits.lshift(1,k)),my_arithtemp'); ! 840: M.beq(false,my_arithtemp',Reg 0,label)) ! 841: | bbs _ = ErrorMsg.impossible "bbs args don't match in mips" ! 842: ! 843: \endcode ! 844: \begincode{40} ! 845: \moddef{DEBUG code}\endmoddef ! 846: val ibranch = diag "ibranch" ibranch ! 847: val jmp = diag "jmp" jmp ! 848: val bbs = diag "bbs" bbs ! 849: ! 850: \endcode ! 851: \begindocs{41} ! 852: We decided not to include floating point registers in our galaxy of ! 853: effective addresses. ! 854: This means that floating point registers are used only at this level, and ! 855: only to contain intermediate results. ! 856: All operands and final results will be stored in memory, in the usual ! 857: ML format (i.e. as 8-byte strings). ! 858: ! 859: In fact, we can be much more strict than that, and claim that ! 860: all floating point operands will live in FPR0 and FPR2, and that all ! 861: results will appear in FPR0. ! 862: ! 863: We don't make a distinction between general-purpose and floating point ! 864: registers; it's up to the instructions to know the difference. ! 865: \enddocs ! 866: \begincode{42} ! 867: \moddef{floating point}\endmoddef ! 868: val floatop1 = Reg 0 ! 869: val floatop2 = Reg 2 ! 870: val floatresult = Reg 0 ! 871: ! 872: \endcode ! 873: \begindocs{43} ! 874: One very common operation is to take the result of a floating point ! 875: operation and put it into a fresh record, newly allocated on the heap. ! 876: This operation is traditionally called \code{}finish_real\edoc{}, and it takes one ! 877: argument, the destination register for the new value. ! 878: All real values on the heap are labelled as 8-byte strings. ! 879: To store a floating point, we store the least significant ! 880: word in the lower address, but we store the most significant word ! 881: first, in case that triggers a garbage collection. ! 882: \enddocs ! 883: \begincode{44} ! 884: \moddef{floating point}\endmoddef ! 885: val real_tag = Immed(8*System.Tags.power_tags + System.Tags.tag_string) ! 886: ! 887: fun store_float(Reg n,ea,offset) = ! 888: if n mod 2 <> 0 then ErrorMsg.impossible "bad float reg in mips" ! 889: else (M.swc1(Reg (n+1),ea,offset+4);M.swc1(Reg n,ea,offset)) ! 890: ! 891: fun finish_real (Direct result) = ( ! 892: store_float(floatresult,dataptr,4); ! 893: M.move(real_tag,my_arithtemp'); ! 894: M.sw(my_arithtemp',dataptr,0); ! 895: M.add(dataptr',Immed 4,result); ! 896: M.add(dataptr',Immed 12,dataptr')) ! 897: | finish_real _ = ! 898: ErrorMsg.impossible "ptr to result of real operation not register in mips" ! 899: ! 900: \endcode ! 901: \begindocs{45} ! 902: Loading a floating point quantity is analogous. ! 903: \enddocs ! 904: \begincode{46} ! 905: \moddef{floating point}\endmoddef ! 906: fun load_float(Reg dest,src,offset) = ! 907: if dest mod 2 <> 0 then ErrorMsg.impossible "bad float reg in mips" ! 908: else (M.lwc1(Reg dest,src,offset); M.lwc1(Reg (dest+1),src,offset+4)) ! 909: ! 910: \endcode ! 911: \begindocs{47} ! 912: Now we can do a general two- and three-operand floating point operationa. ! 913: The only parameter is the function in \code{}MipsCoder\edoc{} that ! 914: emits the floating point register operation. ! 915: \enddocs ! 916: \begincode{48} ! 917: \moddef{floating point}\endmoddef ! 918: fun two_float instruction (op1,result) = ( ! 919: load_float(floatop1,op1,0); ! 920: instruction(floatop1,floatresult); ! 921: finish_real(result)) ! 922: ! 923: fun three_float instruction (op1,op2,result) = ( ! 924: load_float(floatop1,op1,0); ! 925: load_float(floatop2,op2,0); ! 926: instruction(floatop1,floatop2,floatresult); ! 927: finish_real(result)) ! 928: ! 929: \endcode ! 930: \begindocs{49} ! 931: That takes care of everything except branch ! 932: \enddocs ! 933: \begincode{50} ! 934: \moddef{floating point}\endmoddef ! 935: val mnegg = two_float M.neg_double ! 936: val mulg3 = three_float M.mul_double ! 937: val divg3 = three_float M.div_double ! 938: val addg3 = three_float M.add_double ! 939: val subg3 = three_float M.sub_double ! 940: ! 941: ! 942: \endcode ! 943: \begindocs{51} ! 944: The Mips doesn't provide all six comparisons in hardware, so the ! 945: next function does the comparison using only less than and equal. ! 946: The result tells \code{}bcop1\edoc{} whether to branch on condition true ! 947: or condition false. ! 948: \enddocs ! 949: \begincode{52} ! 950: \moddef{floating point compare}\endmoddef ! 951: fun compare(LSS,op1,op2) = (M.slt_double(op1,op2); true) ! 952: | compare(GEQ,op1,op2) = (M.slt_double(op1,op2); false) ! 953: | compare(EQL,op1,op2) = (M.seq_double(op1,op2); true) ! 954: | compare(NEQ,op1,op2) = (M.seq_double(op1,op2); false) ! 955: | compare(LEQ,op1,op2) = compare(GEQ,op2,op1) ! 956: | compare(GTR,op1,op2) = compare(LSS,op2,op1) ! 957: \endcode ! 958: \begincode{53} ! 959: \moddef{floating point}\endmoddef ! 960: local ! 961: \LA{}floating point compare\RA{} ! 962: in ! 963: fun gbranch (cond, op1, op2, Immedlab label) = ( ! 964: load_float(floatop1,op1,0); ! 965: load_float(floatop2,op2,0); ! 966: M.bcop1(compare(cond,floatop1,floatop2),label)) ! 967: | gbranch _ = ErrorMsg.impossible "insane gbranch target in mips.nw" ! 968: end ! 969: ! 970: ! 971: \endcode ! 972: \begindocs{54} ! 973: When a function begins execution, it checks to make sure there is sufficient ! 974: memory available that it can do all its allocation. ! 975: generic does this by calling \code{}checkLimit : int -> unit\edoc{}. ! 976: At the moment, we implement this check by doing a store, ! 977: taking advantage of the virtual memory hardware, which will cause an exception ! 978: if there's not enough memory. ! 979: Later we will replace this store with a check against a limit register, ! 980: which will avoid virtual memory hacking and which will have advantages ! 981: for concurrency. ! 982: \enddocs ! 983: \begincode{55} ! 984: \moddef{memory check}\endmoddef ! 985: fun checkLimit max_allocation = M.sw(Reg 0, dataptr, max_allocation-4) ! 986: (* store zero in last location to be used *) ! 987: ! 988: \endcode ! 989: \begindocs{56} ! 990: These two functions have null implementations. ! 991: \code{}beginStdFn\edoc{} is necessary only on the SPARC, since that machine needs to get ! 992: its program counter, and it is awkward to do so in the middle of a function. ! 993: ! 994: \code{}profile\edoc{} is a mysterious relic. ! 995: \enddocs ! 996: \begincode{57} ! 997: \moddef{omitted functions}\endmoddef ! 998: fun beginStdFn _ = () (* do nothing, just like the Vax *) ! 999: ! 1000: fun profile(i,incr) = () ! 1001: ! 1002: \endcode ! 1003: \filename{mipscoder.nw} ! 1004: \begindocs{0} ! 1005: \input verbatim ! 1006: \input itemize ! 1007: \chapter{A small assembler for the MIPS} ! 1008: This is part of the code generator for Standard ML of New Jersey. ! 1009: We generate code in several stages. ! 1010: This is nearly the lowest stage; it is like an assembler. ! 1011: The user can call any function in the MIPSCODER signature. ! 1012: Each one corresponds to an assembler pseudo-instruction. ! 1013: Most correspond to single MIPS instructions. ! 1014: The assembler remembers all the instructions that have been ! 1015: requested, and when \code{}codegen\edoc{} is called it generates MIPS ! 1016: code for them. ! 1017: ! 1018: Some other structure will be able to use the MIPS structure to implement ! 1019: a \code{}CMACHINE\edoc{}, which is the abstract machine that ML thinks it is running ! 1020: on. ! 1021: (What really happens is a functor maps some structure ! 1022: implementing \code{}MIPSCODER\edoc{} to a different structure implementing ! 1023: \code{}CMACHINE\edoc{}.) ! 1024: ! 1025: {\em Any function using a structure of this signature must avoid ! 1026: touching registers 1~and~31. ! 1027: Those registers are reserved for use by the assembler.} ! 1028: ! 1029: \enddocs ! 1030: \begindocs{1} ! 1031: Here is the signature of the assembler, \code{}MIPSCODER\edoc{}. ! 1032: It can be extracted from this file by ! 1033: $$\hbox{\tt notangle mipsinstr.nw -Rsignature}.$$ ! 1034: \enddocs ! 1035: \begincode{2} ! 1036: \moddef{signature}\endmoddef ! 1037: signature MIPSCODER = sig ! 1038: ! 1039: (* Assembler for the MIPS chip *) ! 1040: ! 1041: eqtype Label ! 1042: datatype Register = Reg of int ! 1043: (* Registers 1 and 31 are reserved for use by this assembler *) ! 1044: datatype EA = Direct of Register | Immed of int | Immedlab of Label ! 1045: (* effective address *) ! 1046: ! 1047: structure M : sig ! 1048: ! 1049: (* Emit various constants into the code *) ! 1050: ! 1051: val emitstring : string -> unit (* put a literal string into the ! 1052: code (null-terminated?) and ! 1053: extend with nulls to 4-byte ! 1054: boundary. Just chars, no ! 1055: descriptor or length *) ! 1056: val realconst : string -> unit (* emit a floating pt literal *) ! 1057: (* NOT RIGHT YET *) ! 1058: val emitlong : int -> unit (* emit a 4-byte integer literal *) ! 1059: ! 1060: ! 1061: (* Label bindings and emissions *) ! 1062: ! 1063: val newlabel : unit -> Label (* new, unbound label *) ! 1064: val define : Label -> unit (* cause the label to be bound to ! 1065: the code about to be generated *) ! 1066: val emitlab : int * Label -> unit (* L3: emitlab(k,L2) is equivalent to ! 1067: L3: emitlong(k+L2-L3) *) ! 1068: ! 1069: (* Control flow instructions *) ! 1070: ! 1071: val slt : Register * EA * Register -> unit ! 1072: (* (operand1, operand2, result) *) ! 1073: (* set less than family *) ! 1074: val beq : bool * Register * Register * Label -> unit ! 1075: (* (beq or bne, operand1, operand2, branch address) *) ! 1076: (* branch equal/not equal family *) ! 1077: ! 1078: val jump : Register -> unit (* jump register instruction *) ! 1079: ! 1080: val slt_double : Register * Register -> unit ! 1081: (* floating pt set less than *) ! 1082: val seq_double : Register * Register -> unit ! 1083: (* floating pt set equal *) ! 1084: val bcop1 : bool * Label -> unit (* floating pt conditional branch *) ! 1085: ! 1086: ! 1087: (* Arithmetic instructions *) ! 1088: (* arguments are (operand1, operand2, result) *) ! 1089: ! 1090: val add : Register * EA * Register -> unit ! 1091: val and' : Register * EA * Register -> unit ! 1092: val or : Register * EA * Register -> unit ! 1093: val xor : Register * EA * Register -> unit ! 1094: val sub : Register * Register * Register -> unit ! 1095: val div : Register * Register * Register -> unit ! 1096: val mult : Register * Register * Register -> unit ! 1097: val mfhi : Register -> unit (* high word of 64-bit multiply *) ! 1098: ! 1099: (* Floating point arithmetic *) ! 1100: ! 1101: val neg_double : Register * Register -> unit ! 1102: val mul_double : Register * Register * Register -> unit ! 1103: val div_double : Register * Register * Register -> unit ! 1104: val add_double : Register * Register * Register -> unit ! 1105: val sub_double : Register * Register * Register -> unit ! 1106: ! 1107: (* Move pseudo-instruction : move(src,dest) *) ! 1108: ! 1109: val move : EA * Register -> unit ! 1110: ! 1111: (* Load and store instructions *) ! 1112: (* arguments are (destination, source address, offset) *) ! 1113: ! 1114: val lbu : Register * EA * int -> unit (* bytes *) ! 1115: val sb : Register * EA * int -> unit ! 1116: val lw : Register * EA * int -> unit (* words *) ! 1117: val sw : Register * EA * int -> unit ! 1118: val lwc1: Register * EA * int -> unit (* floating point coprocessor *) ! 1119: val swc1: Register * EA * int -> unit ! 1120: val lui : Register * int -> unit ! 1121: ! 1122: (* Shift instructions *) ! 1123: (* arguments are (shamt, operand, result) *) ! 1124: (* shamt as Immedlab _ is senseless *) ! 1125: ! 1126: val sll : EA * Register * Register -> unit ! 1127: val sra : EA * Register * Register -> unit ! 1128: ! 1129: ! 1130: (* Miscellany *) ! 1131: ! 1132: val align : unit -> unit (* cause next data to be emitted on ! 1133: a 4-byte boundary *) ! 1134: val mark : unit -> unit (* emit a back pointer, ! 1135: also called mark *) ! 1136: ! 1137: val comment : string -> unit ! 1138: ! 1139: end (* signature of structure M *) ! 1140: ! 1141: val codegen : (int * int -> unit) * (int -> string -> unit) ! 1142: * (string -> unit) -> unit ! 1143: ! 1144: val codestats : outstream -> unit (* write statistics on stream *) ! 1145: ! 1146: end (* signature MIPSCODER *) ! 1147: \endcode ! 1148: \begindocs{3} ! 1149: The basic strategy of the implementation is to hold on, via the \code{}kept\edoc{} ! 1150: pointer, to the list of instructions generated so far. ! 1151: We use \code{}instr\edoc{} for the type of an instruction, so ! 1152: \code{}kept\edoc{} has type \code{}instr list ref\edoc{}. ! 1153: ! 1154: The instructions will be executed in the following order: the ! 1155: instruction at the head of the \code{}!kept\edoc{} is executed last. ! 1156: This enables us to accept calls in the order of execution but ! 1157: add the new instruction(s) to the list in constant time. ! 1158: ! 1159: ! 1160: \enddocs ! 1161: \begindocs{4} ! 1162: ! 1163: We structure the instruction stream a little bit by factoring ! 1164: out the difference between multiplication and division; these ! 1165: operations are treated identically in that the result has to be ! 1166: fetched out of the MIPS' LO register. ! 1167: ! 1168: We also factor the different of load and store instructions that can ! 1169: occur: we have load byte, load word, and load to coprocessor (floating point). ! 1170: \enddocs ! 1171: \begincode{5} ! 1172: \moddef{types auxiliary to \code{}instr\edoc{}}\endmoddef ! 1173: datatype size = Byte | Word | Floating ! 1174: datatype muldiv = MULT | DIV ! 1175: \endcode ! 1176: \begindocs{6} ! 1177: ! 1178: Here are the instructions that exist. ! 1179: We list them in more or less the order of the MIPSCODER signature. ! 1180: \enddocs ! 1181: \begincode{7} ! 1182: \moddef{definition of \code{}instr\edoc{}}\endmoddef ! 1183: \LA{}types auxiliary to \code{}instr\edoc{}\RA{} ! 1184: ! 1185: datatype instr = ! 1186: STRINGCONST of string (* constants *) ! 1187: | REALCONST of string ! 1188: | EMITLONG of int ! 1189: ! 1190: | DEFINE of Label (* labels *) ! 1191: | EMITLAB of int * Label ! 1192: ! 1193: | SLT of Register * EA * Register (* control flow *) ! 1194: | BEQ of bool * Register * Register * Label ! 1195: | JUMP of Register ! 1196: | SLT_D of Register * Register ! 1197: | SEQ_D of Register * Register ! 1198: | BCOP1 of bool * Label ! 1199: ! 1200: | NOP (* no-op for delay slot *) ! 1201: ! 1202: | ADD of Register * EA * Register (* arithmetic *) ! 1203: | AND of Register * EA * Register ! 1204: | OR of Register * EA * Register ! 1205: | XOR of Register * EA * Register ! 1206: | SUB of Register * Register * Register ! 1207: | MULDIV of muldiv * Register * Register ! 1208: | MFLO of Register (* mflo instruction used with ! 1209: 64-bit multiply and divide *) ! 1210: | MFHI of Register ! 1211: ! 1212: | NEG_D of Register * Register ! 1213: | MUL_D of Register * Register * Register ! 1214: | DIV_D of Register * Register * Register ! 1215: | ADD_D of Register * Register * Register ! 1216: | SUB_D of Register * Register * Register ! 1217: ! 1218: | MOVE of EA * Register (* put something into a register *) ! 1219: | LDI_32 of int * Register (* load in a big immediate constant (>16 bits) *) ! 1220: | LUI of Register * int (* Mips lui instruction *) ! 1221: ! 1222: | LOAD of size * Register * EA * int (* load and store *) ! 1223: | STORE of size * Register * EA * int ! 1224: ! 1225: | SLL of EA * Register * Register (* shift *) ! 1226: | SRA of EA * Register * Register ! 1227: ! 1228: | COMMENT of string (* generates nothing *) ! 1229: | MARK (* a backpointer *) ! 1230: \endcode ! 1231: \begindocs{8} ! 1232: ! 1233: Here is the code that handles the generated stream, \code{}kept\edoc{}. ! 1234: It begins life as \code{}nil\edoc{} and returns to \code{}nil\edoc{} every time code is ! 1235: generated. ! 1236: The function \code{}keep\edoc{} is a convenient way of adding a single \code{}instr\edoc{} to ! 1237: the list; it's very terse. ! 1238: Sometimes we have to add multiple \code{}instr\edoc{}s; then we use \code{}keeplist\edoc{}. ! 1239: We also define a function \code{}delay\edoc{} that is just like a \code{}keep\edoc{} but ! 1240: it adds a NOP in the delay slot. ! 1241: \enddocs ! 1242: \begincode{9} ! 1243: \moddef{instruction stream and its functions}\endmoddef ! 1244: val kept = ref nil : instr list ref ! 1245: fun keep f a = kept := f a :: !kept ! 1246: fun delay f a = kept := NOP :: f a :: !kept ! 1247: fun keeplist l = kept := l @ !kept ! 1248: \endcode ! 1249: \begincode{10} ! 1250: \moddef{reinitialize \code{}kept\edoc{}}\endmoddef ! 1251: kept := nil ! 1252: \endcode ! 1253: \begindocs{11} ! 1254: ! 1255: \subsection{Exporting functions for \code{}MIPSCODER\edoc{}} ! 1256: We now know enough to implement most of the functions called for in ! 1257: \code{}MIPSCODER\edoc{}. ! 1258: We still haven't decided on an implementation of labels, ! 1259: and there is one subtlety in multiplication and division, ! 1260: but the rest is set. ! 1261: \enddocs ! 1262: \begincode{12} ! 1263: \moddef{\code{}MIPSCODER\edoc{} functions}\endmoddef ! 1264: val emitstring = keep STRINGCONST (* literals *) ! 1265: val realconst = keep REALCONST ! 1266: val emitlong = keep EMITLONG ! 1267: ! 1268: \LA{}label functions\RA{} (* labels *) ! 1269: ! 1270: val slt = keep SLT (* control flow *) ! 1271: val beq = delay BEQ ! 1272: val jump = delay JUMP ! 1273: val slt_double = delay SLT_D ! 1274: val seq_double = delay SEQ_D ! 1275: val bcop1 = delay BCOP1 ! 1276: ! 1277: val add = keep ADD (* arithmetic *) ! 1278: val and' = keep AND ! 1279: val or = keep OR ! 1280: val xor = keep XOR ! 1281: val op sub = keep SUB ! 1282: \LA{}multiplication and division functions\RA{} ! 1283: ! 1284: val neg_double = keep NEG_D ! 1285: val mul_double = keep MUL_D ! 1286: val div_double = keep DIV_D ! 1287: val add_double = keep ADD_D ! 1288: val sub_double = keep SUB_D ! 1289: ! 1290: val move = keep MOVE ! 1291: ! 1292: fun lbu (a,b,c) = delay LOAD (Byte,a,b,c) (* load and store *) ! 1293: fun lw (a,b,c) = delay LOAD (Word,a,b,c) ! 1294: fun lwc1 (a,b,c) = delay LOAD (Floating,a,b,c) ! 1295: fun sb (a,b,c) = keep STORE (Byte,a,b,c) ! 1296: fun sw (a,b,c) = keep STORE (Word,a,b,c) ! 1297: fun swc1 (a,b,c) = delay STORE (Floating,a,b,c) ! 1298: val lui = keep LUI ! 1299: ! 1300: val sll = keep SLL (* shift *) ! 1301: val sra = keep SRA ! 1302: ! 1303: fun align() = () (* never need to align on MIPS *) ! 1304: val mark = keep (fn () => MARK) ! 1305: val comment = keep COMMENT ! 1306: \endcode ! 1307: \begindocs{13} ! 1308: ! 1309: Multiplication and division have a minor complication; the ! 1310: result has to be fetched from the LO register. ! 1311: \enddocs ! 1312: \begincode{14} ! 1313: \moddef{multiplication and division functions}\endmoddef ! 1314: fun muldiv f (a,b,c) = keeplist [MFLO c, MULDIV (f,a,b)] ! 1315: val op div = muldiv DIV ! 1316: val mult = muldiv MULT ! 1317: val mfhi = keep MFHI ! 1318: \endcode ! 1319: \begindocs{15} ! 1320: ! 1321: For now, labels are just pointers to integers. ! 1322: During code generation, those integers will be set to positions ! 1323: in the instruction stream, and then they'll be useful as addresses ! 1324: relative to the program counter pointer (to be held in \code{}Reg pcreg\edoc{}). ! 1325: \enddocs ! 1326: \begincode{16} ! 1327: \moddef{definition of \code{}Label\edoc{}}\endmoddef ! 1328: type Label = int ref ! 1329: \endcode ! 1330: \begincode{17} ! 1331: \moddef{label functions}\endmoddef ! 1332: fun newlabel () = ref 0 ! 1333: val define = keep DEFINE ! 1334: val emitlab = keep EMITLAB ! 1335: \endcode ! 1336: \begindocs{18} ! 1337: ! 1338: Here's the overall plan of this structure: ! 1339: \enddocs ! 1340: \begincode{19} ! 1341: \moddef{*}\endmoddef ! 1342: structure MipsCoder : MIPSCODER = struct ! 1343: ! 1344: \LA{}definition of \code{}Label\edoc{}\RA{} ! 1345: ! 1346: datatype Register = Reg of int ! 1347: ! 1348: datatype EA = Direct of Register ! 1349: | Immed of int ! 1350: | Immedlab of Label ! 1351: ! 1352: \LA{}definition of \code{}instr\edoc{}\RA{} ! 1353: ! 1354: \LA{}instruction stream and its functions\RA{} ! 1355: ! 1356: structure M = struct ! 1357: \LA{}\code{}MIPSCODER\edoc{} functions\RA{} ! 1358: end ! 1359: ! 1360: open M ! 1361: ! 1362: \LA{}functions that assemble \code{}instr\edoc{}s into code\RA{} ! 1363: ! 1364: \LA{}statistics\RA{} ! 1365: ! 1366: end (* MipsInstr *) ! 1367: \endcode ! 1368: \begindocs{20} ! 1369: \subsection{Sizes of \code{}instr\edoc{}s} ! 1370: Now let's consider the correspondence between our \code{}instr\edoc{} type and the ! 1371: actual MIPS instructions we intend to emit. ! 1372: One important problem to solve is figuring out how big things are, ! 1373: so that we know what addresses to generate for the various labels. ! 1374: We will also want to know what address is currently stored in the program ! 1375: counter regsiter (\code{}pcreg\edoc{}), ! 1376: because we'll need to know when something is close ! 1377: enough that we can use a sixteen-bit address relative to that register. ! 1378: The kind of address we can use will determine how big things are. ! 1379: ! 1380: We'll rearrange the code so that we have a list of \code{}ref int * instr\edoc{} pairs, ! 1381: where the \code{}ref int\edoc{} stores the position in the list. ! 1382: (Positions start at zero.) ! 1383: Since in the MIPS all instructions are the same size, we measure ! 1384: position as number of instructions. ! 1385: While we're at it, we reverse the list so that the head will execute first, ! 1386: then the rest of the list. ! 1387: ! 1388: We begin with each position set to zero, and make a pass over the list ! 1389: trying to set the value of each position. ! 1390: We do this by estimating the size of (number of MIPS instructions ! 1391: generated for) each \code{}instr\edoc{}. ! 1392: Since there are forward references, we may not have all the distances right ! 1393: the first time, so we have to make a second pass. ! 1394: But during this second pass we could find that something is further ! 1395: away than we thought, and we have to switch from using a pc-relative mode to ! 1396: something else (or maybe grab the new pc?), which changes the size again, ! 1397: and moves things even further away. ! 1398: Because we can't control this process, we just keep making passes over the ! 1399: list until the process quiesces (we get the same size twice). ! 1400: ! 1401: In order to guarantee termination, we have to make sure later passes only ! 1402: increase the sizes of things. ! 1403: This is sufficient since there is a maximum number of MIPS instructions ! 1404: we can generate for each \code{}instr\edoc{}. ! 1405: ! 1406: ! 1407: While we're at it, we might want to complicate things by making the function ! 1408: that does the passes also emit code. ! 1409: For a single pass we hand an optional triple of emitters, the initial position, ! 1410: an \code{}int option\edoc{} for the program counter pointer (if known), and the ! 1411: instructions. ! 1412: ! 1413: ! 1414: ! 1415: I'm not sure what explains the use of the \code{}ref int\edoc{} to track the position, ! 1416: instead of just an \code{}int\edoc{}---it might be a desire to avoid the ! 1417: overhead of creating a bunch of new objects, or it might be really hard ! 1418: to do the passes cheaply. ! 1419: It should think a variation on \code{}map\edoc{} would do the job, but maybe I'm ! 1420: missing something. ! 1421: ! 1422: \enddocs ! 1423: \begindocs{21} ! 1424: \code{}emitters\edoc{} is actually a triple \code{}emit,emit_string,emit_real\edoc{}. ! 1425: \code{}emit : int * int -> unit\edoc{} emits one instruction, ! 1426: and \code{}emit_string : int -> string -> unit\edoc{} emits a string constant. ! 1427: \code{}emit_string\edoc{} could be specified as a function of \code{}emit\edoc{}, ! 1428: but the nature of the function would depend on whether the target ! 1429: machine was little-endian or big-endian, and we don't want to have ! 1430: that dependency built in. ! 1431: \code{}emit_real : string -> unit\edoc{} emits two words corresponding to an IEEE ! 1432: floating point constant in string form (e.g. \code{}"3.14159"\edoc{}). ! 1433: In principle, it can always be derived from \code{}emit_word\edoc{}, but it's ! 1434: easier to pass it in because then we can use John Reppy's code; ! 1435: see the \code{}MipsReal\edoc{} functor for more details, as well as ! 1436: \code{}mipsglue.sml\edoc{}. ! 1437: ! 1438: ! 1439: \code{}instrs\edoc{} is the ! 1440: list of instructions (in execute-head-last order). ! 1441: ! 1442: The second argument to \code{}pass\edoc{} indicates for what instructions code ! 1443: is to be generated. ! 1444: It is a record (position of next instruction, program counter pointer if any, ! 1445: remaining instructions to generate [with positions]). ! 1446: ! 1447: \indent \code{}prepare\edoc{} produces two results: the instruction stream with ! 1448: size pointers added, and the total size of code to be generated. ! 1449: We add the total size because that is the only way to find the number ! 1450: of \code{}bltzal\edoc{}s, which are implicit in the instruction stream. ! 1451: ! 1452: \enddocs ! 1453: \begincode{22} ! 1454: \moddef{assembler}\endmoddef ! 1455: fun prepare instrs = ! 1456: let fun add_positions(done, inst::rest) = ! 1457: add_positions( (ref 0, inst) :: done, rest) ! 1458: | add_positions(done, nil) = done ! 1459: ! 1460: val instrs' = add_positions(nil, instrs) (* reverse and add \code{}ref int\edoc{}s*) ! 1461: ! 1462: fun passes(oldsize) = ! 1463: (* make passes with no emission until size is stable*) ! 1464: let val size = pass NONE (0,NONE,instrs') ! 1465: in if size=oldsize then size ! 1466: else passes size ! 1467: end ! 1468: in \{size = passes 0, stream = instrs'\} ! 1469: end ! 1470: ! 1471: fun assemble emitters instrs = ! 1472: pass (SOME emitters) (0,NONE,#stream (prepare instrs)) ! 1473: ! 1474: \endcode ! 1475: \begincode{23} ! 1476: \moddef{functions that assemble \code{}instr\edoc{}s into code}\endmoddef ! 1477: fun get (SOME x) = x ! 1478: | get NONE = ErrorMsg.impossible "missing pcptr in mipscoder" ! 1479: ! 1480: \LA{}\code{}pcptr\edoc{} functions\RA{} ! 1481: \LA{}single pass\RA{} ! 1482: \LA{}assembler\RA{} ! 1483: ! 1484: fun codegen emitters = ( ! 1485: assemble emitters (!kept); ! 1486: \LA{}reinitialize \code{}kept\edoc{}\RA{} ! 1487: ) ! 1488: \endcode ! 1489: \begindocs{24} ! 1490: ! 1491: The program counter pointer is a device that enables us to to addressing ! 1492: relative to the pcp register, register 31. ! 1493: The need for it arises when we want to access a data element which we know ! 1494: only by its label. ! 1495: The labels give us addresses relative to the beginning of the function, ! 1496: but we can only use addresses relative to some register. ! 1497: The answer is to set register~31 with a \code{}bltzal\edoc{} instruction, ! 1498: then use that for addressing. ! 1499: ! 1500: The function \code{}needs_a_pcptr\edoc{} determines when it is necessary ! 1501: to have a known value in register~31. ! 1502: That is, we need the program counter pointer ! 1503: \itemize ! 1504: \item ! 1505: at \code{}NOP\edoc{} for a reason to be named later? ! 1506: \item ! 1507: at any operation that uses an effective address that refers to a label ! 1508: (since all labels have to be relative to the program counter). ! 1509: \item ! 1510: BEQ's and BCOP1's to very far away, ! 1511: since we have to compute the address for a JUMP ! 1512: knowing the value of the program counter pointer. ! 1513: \enditemize ! 1514: \enddocs ! 1515: \begincode{25} ! 1516: \moddef{\code{}pcptr\edoc{} functions}\endmoddef ! 1517: fun needs_a_pcptr(_,SLT(_,Immedlab _,_)) = true ! 1518: | needs_a_pcptr(_,ADD(_,Immedlab _,_)) = true ! 1519: | needs_a_pcptr(_,AND(_,Immedlab _,_)) = true ! 1520: | needs_a_pcptr(_,OR(_,Immedlab _,_)) = true ! 1521: | needs_a_pcptr(_,XOR(_,Immedlab _,_)) = true ! 1522: | needs_a_pcptr(_,MOVE(Immedlab _,_)) = true ! 1523: | needs_a_pcptr(_,LOAD(_,_,Immedlab _,_)) = true ! 1524: | needs_a_pcptr(_,STORE(_,_,Immedlab _,_)) = true ! 1525: | needs_a_pcptr(_,SLL(Immedlab _,_,_)) = true ! 1526: | needs_a_pcptr(_,SRA(Immedlab _,_,_)) = true ! 1527: | needs_a_pcptr(1, BEQ _) = false (* small BEQ's dont need pcptr *) ! 1528: | needs_a_pcptr(_, BEQ _) = true (* but large ones do *) ! 1529: | needs_a_pcptr(1, BCOP1 _) = false (* small BCOP1's dont need pcptr *) ! 1530: | needs_a_pcptr(_, BCOP1 _) = true (* but large ones do *) ! 1531: | needs_a_pcptr _ = false ! 1532: \endcode ! 1533: \begindocs{26} ! 1534: ! 1535: Creating the program counter pointer once, with a \code{}bltzal\edoc{}, is not ! 1536: enough; we have to invalidate the program counter pointer at every ! 1537: label, since control could arrive at the label from God knows where, and ! 1538: therefore we don't know what the program counter pointer is. ! 1539: ! 1540: We use the function \code{}makepcptr\edoc{} to create a new program counter pointer ! 1541: ``on the fly'' while generating code for other \code{}instrs\edoc{}. ! 1542: (I chose not to create a special \code{}instr\edoc{} for \code{}bltzal\edoc{}, which I ! 1543: could have inserted at appropriate points in the instruction stream.) ! 1544: To try and find an odd bug, I'm adding no-ops after each \code{}bltzal\edoc{}. ! 1545: I don't really believe they're necessary. ! 1546: ! 1547: The function \code{}gen\edoc{}, which generates the instructions (or computes ! 1548: their size), takes three arguments. ! 1549: Third: the list of instructions to be generated (paired with pointers ! 1550: to their sizes); first: the position (in words) at which to generate ! 1551: those instructions; second: the current value of the program counter ! 1552: pointer (register~31), if known. ! 1553: ! 1554: The mutual recursion between \code{}gen\edoc{} and \code{}makepcptr\edoc{} maintains ! 1555: the program counter pointer. ! 1556: \code{}gen\edoc{} invalidates it at labels, and calls \code{}makepcptr\edoc{} to create a valid ! 1557: one when necessary (as determined by \code{}needs_a_pcptr\edoc{}). ! 1558: \enddocs ! 1559: \begincode{27} ! 1560: \moddef{single pass}\endmoddef ! 1561: fun pass emitters = ! 1562: let fun makepcptr(i,x) = ! 1563: (* may need to emit NOP for delay slot if next instr is branch *) ! 1564: let val size = case x of ((_,BEQ _)::rest) => 2 ! 1565: | ((_,BCOP1 _)::rest) => 2 ! 1566: | _ => 1 ! 1567: in case emitters of NONE => () ! 1568: | SOME (emit, _, _ ) => ( ! 1569: emit(Opcodes.bltzal(0,0)); ! 1570: if size=2 then emit(Opcodes.add(0,0,0)) else ()); ! 1571: gen(i+size, SOME (i+2), x) ! 1572: end ! 1573: and gen(i,_,nil) = i ! 1574: | gen(i, _, (_,DEFINE lab) :: rest) = (lab := i; gen(i,NONE, rest)) ! 1575: (* invalidate the pc pointer at labels *) ! 1576: (* may want to do special fiddling with NOPs *) ! 1577: | gen(pos, pcptr, x as ((sizeref as ref size, inst) :: rest)) = ! 1578: if (pcptr=NONE andalso needs_a_pcptr(size, inst)) then makepcptr(pos,x) ! 1579: else case emitters of ! 1580: SOME (emit : int*int -> unit, emit_string : int -> string -> unit, ! 1581: emit_real : string -> unit) => ! 1582: \LA{}emit MIPS instructions\RA{} ! 1583: | NONE => ! 1584: \LA{}compute positions\RA{} ! 1585: in gen ! 1586: end ! 1587: ! 1588: \endcode ! 1589: \begindocs{28} ! 1590: \subsection{Generating the instructions} ! 1591: Now we need to consider the nitty-gritty details of just what instructions ! 1592: are generated for each \code{}instr\edoc{}. ! 1593: In early passes, we'll just need to know how many instructions are ! 1594: required (and that number may change from pass to pass, so it must be ! 1595: recomputed). ! 1596: In the last pass, the sizes are stable (by definition), so we can look ! 1597: at the sizes to see what instructions to generate. ! 1598: ! 1599: We'll consider the \code{}instrs\edoc{} in groups, but first, here's the ! 1600: way we will structure things: ! 1601: \enddocs ! 1602: \begincode{29} ! 1603: \moddef{compute positions}\endmoddef ! 1604: let \LA{}functions for computing sizes\RA{} ! 1605: val newsize = case inst of ! 1606: \LA{}cases for sizes to be computed\RA{} ! 1607: in if newsize > size then sizeref := newsize else (); ! 1608: gen(pos+(!sizeref) (* BUGS -- was pos+size*),pcptr,rest) ! 1609: end ! 1610: \endcode ! 1611: \begincode{30} ! 1612: \moddef{emit MIPS instructions}\endmoddef ! 1613: let fun gen1() = gen(pos+size,pcptr,rest) ! 1614: (* generate the rest of the \code{}instr\edoc{}s *) ! 1615: open Bits ! 1616: open Opcodes ! 1617: \LA{}declare reserved registers \code{}tempreg\edoc{} and \code{}pcreg\edoc{}\RA{} ! 1618: \LA{}functions for emitting instructions\RA{} ! 1619: in case inst of ! 1620: \LA{}cases of instructions to be emitted\RA{} ! 1621: end ! 1622: \endcode ! 1623: \begindocs{31} ! 1624: When we get around to generating code, we may need to use a temporary ! 1625: register. ! 1626: For example, if we want to load into a register ! 1627: an immediate constant that won't fit ! 1628: into 16~bits, we will have to load the high-order part of the constant ! 1629: with \code{}lui\edoc{}, then use \code{}addi\edoc{} to add then the low-order part. ! 1630: The MIPS assembler has a similar problem, and on page D-2 of ! 1631: the MIPS book we notice that register~1 is reserved for the use of the ! 1632: assembler. ! 1633: So we do the same. ! 1634: ! 1635: We need to reserve a second register for use in pointing to the program ! 1636: counter. ! 1637: We will use register 31 because the \code{}bltzal\edoc{} instruction automatically ! 1638: sets register 31 to the PC. ! 1639: \enddocs ! 1640: \begincode{32} ! 1641: \moddef{declare reserved registers \code{}tempreg\edoc{} and \code{}pcreg\edoc{}}\endmoddef ! 1642: val tempreg = 1 ! 1643: val pcreg = 31 ! 1644: \endcode ! 1645: \begindocs{33} ! 1646: ! 1647: Before showing the code for the actual instructions, we should ! 1648: point out that ! 1649: we have two different ways of emitting a long word. ! 1650: \code{}emitlong\edoc{} just splits the bits into two pieces for those cases ! 1651: when it's desirable to put a word into the memory image. ! 1652: \code{}split\edoc{} gives something that will load correctly ! 1653: when the high-order piece is loaded into a high-order halfword ! 1654: (using \code{}lui\edoc{}), ! 1655: and the low-order piece is sign-extended and then added to the ! 1656: high-order piece. ! 1657: This is the way we load immediate constants of more than sixteen bits. ! 1658: It is also useful for generating load or store instructions with ! 1659: offsets of more than sixteen bits: we \code{}lui\edoc{} the \code{}hi\edoc{} part and ! 1660: add it to the base regsiter, then use the \code{}lo\edoc{} part as an offset. ! 1661: \enddocs ! 1662: \begincode{34} ! 1663: \moddef{functions for emitting instructions}\endmoddef ! 1664: fun emitlong i = emit(rshift(i,16), andb(i,65535)) ! 1665: (* emit one long word (no sign fiddling) *) ! 1666: fun split i = let val hi = rshift(i,16) and lo = andb(i,65535) ! 1667: in if lo<32768 then (hi,lo) else (hi+1, lo-65536) ! 1668: end ! 1669: ! 1670: \endcode ! 1671: \begindocs{35} ! 1672: We begin implementing \code{}instrs\edoc{} by considering those that emit constants. ! 1673: String constants are padded with nulls out to a word boundary, and ! 1674: real constants take up two words. ! 1675: {\bf At the moment real constants seem to be zeros. ! 1676: One day this will have to be fixed.} ! 1677: Integer constants are just emitted with \code{}emitlong\edoc{}. ! 1678: \enddocs ! 1679: \begincode{36} ! 1680: \moddef{cases for sizes to be computed}\endmoddef ! 1681: STRINGCONST s => Integer.div(String.length(s)+3,4) ! 1682: | REALCONST _ => 2 ! 1683: | EMITLONG _ => 1 ! 1684: \endcode ! 1685: \begincode{37} ! 1686: \moddef{cases of instructions to be emitted}\endmoddef ! 1687: STRINGCONST s => ! 1688: let val s' = s ^ "\\000\\000\\000\\000" ! 1689: in gen1(emit_string (4*size) s') ! 1690: (* doesn't know Big vs Little-Endian *) ! 1691: end ! 1692: | REALCONST s => gen1(emit_real s) (* floating pt constant *) ! 1693: | EMITLONG i => gen1(emitlong i) ! 1694: \endcode ! 1695: \begindocs{38} ! 1696: ! 1697: Next consider the labels. ! 1698: A \code{}DEFINE\edoc{} should never reach this far, and \code{}EMITLAB\edoc{} is almost like ! 1699: an \code{}EMITLONG\edoc{}. ! 1700: \enddocs ! 1701: \begincode{39} ! 1702: \moddef{cases for sizes to be computed}\endmoddef ! 1703: | DEFINE _ => ErrorMsg.impossible "generate code for DEFINE in mipscoder" ! 1704: | EMITLAB _ => 1 ! 1705: \endcode ! 1706: \begincode{40} ! 1707: \moddef{cases of instructions to be emitted}\endmoddef ! 1708: | DEFINE _ => gen1(ErrorMsg.impossible "generate code for DEFINE in mipscoder") ! 1709: | EMITLAB(i, ref d) => gen1(emitlong((d-pos)*4+i)) ! 1710: \endcode ! 1711: \begindocs{41} ! 1712: ! 1713: Now we have to start worrying about instructions with \code{}EA\edoc{} in them. ! 1714: The real difficulty these things present is that they may have an ! 1715: immediate operand that won't fit in 16~bits. ! 1716: So we'll need to get this large immediate operand into a register, ! 1717: sixteen bits at a time, and then do the operation on the register. ! 1718: ! 1719: Since all of the arithmetic instructions have this difficulty, and since ! 1720: we can use them to implement the others, we'll start with those and ! 1721: catch up with the control-flow instructions later. ! 1722: \enddocs ! 1723: \begindocs{42} ! 1724: \code{}SUB\edoc{}, \code{}MULDIV\edoc{}, and \code{}MFLO\edoc{} all use registers only, so they are easy. ! 1725: The other arithmetic operations get treated exactly the same, so we'll ! 1726: use a function to compute the size. ! 1727: {\bf move this to follow the definition of \code{}arith\edoc{}?} ! 1728: \enddocs ! 1729: \begincode{43} ! 1730: \moddef{cases for sizes to be computed}\endmoddef ! 1731: | ADD(_, ea, _) => easize ea ! 1732: | AND(_, ea, _) => easize ea ! 1733: | OR (_, ea, _) => easize ea ! 1734: | XOR(_, ea, _) => easize ea ! 1735: | SUB _ => 1 ! 1736: | MULDIV _ => 1 ! 1737: | MFLO _ => 1 ! 1738: | MFHI _ => 1 ! 1739: \endcode ! 1740: \begindocs{44} ! 1741: Register operations take one instruction. ! 1742: Immediate operations take one instruction for 16~bit constants, ! 1743: and 3 for larger constants (since it costs two instructions to load ! 1744: a big immediate constant into a register). ! 1745: An immediate instruction with \code{}Immedlab l\edoc{} means that the operand ! 1746: is intended to be the machine address associated with that label. ! 1747: To compute that address, we need to add ! 1748: \code{}4*(l-pcptr)\edoc{} to the contents of ! 1749: register~\code{}pcreg\edoc{} (which holds \code{}4*pcptr\edoc{}), ! 1750: put the results in a register, and operate on that register. ! 1751: ! 1752: This tells us enough to compute the sizes. ! 1753: \enddocs ! 1754: \begincode{45} ! 1755: \moddef{functions for computing sizes}\endmoddef ! 1756: fun easize (Direct _) = 1 ! 1757: | easize (Immed i) = if abs(i)<32768 then 1 else 3 ! 1758: | easize (Immedlab(ref lab)) = 1 + easize(Immed (4*(lab-(get pcptr)))) ! 1759: \endcode ! 1760: \begindocs{46} ! 1761: ! 1762: As we have seen, ! 1763: to implement any arithmetic operation, we need to know the register ! 1764: form and the sixteen-bit immediate form. ! 1765: We will also want the operator from \code{}instr\edoc{}, since we do the ! 1766: large immediate via a recursive call. ! 1767: We'll set up a function, \code{}arith\edoc{}, that does the job. ! 1768: \enddocs ! 1769: \begincode{47} ! 1770: \moddef{functions for emitting instructions}\endmoddef ! 1771: fun arith (opr, rform, iform) = ! 1772: let fun ar (Reg op1, Direct (Reg op2), Reg result) = ! 1773: gen1(emit(rform(result,op1,op2))) ! 1774: | ar (Reg op1, Immed op2, Reg result) = ! 1775: (case size of ! 1776: 1 (* 16 bits *) => gen1(emit(iform(result,op1,op2))) ! 1777: | 3 (* 32 bits *) => ! 1778: gen(pos,pcptr, ! 1779: (ref 2, LDI_32(op2, Reg tempreg)):: ! 1780: (ref 1, opr(Reg op1, Direct(Reg tempreg), Reg result)):: ! 1781: rest) ! 1782: | _ => gen(ErrorMsg.impossible ! 1783: "bad size in arith Immed in mipscoder") ! 1784: ) ! 1785: | ar (Reg op1, Immedlab (ref op2), Reg result) = ! 1786: gen(pos, pcptr, ! 1787: (ref (size-1), ! 1788: ADD(Reg pcreg,Immed(4*(op2-(get pcptr))), Reg tempreg)):: ! 1789: (ref 1, opr(Reg op1, Direct(Reg tempreg), Reg result)):: ! 1790: rest) ! 1791: in ar ! 1792: end ! 1793: \endcode ! 1794: \begindocs{48} ! 1795: ! 1796: The generation itself may be a bit anticlimactic. ! 1797: The MIPS has no ``subtract immediate'' instruction, and \code{}SUB\edoc{} has ! 1798: a different type than the others, so we emit it directly. ! 1799: \enddocs ! 1800: \begincode{49} ! 1801: \moddef{cases of instructions to be emitted}\endmoddef ! 1802: | ADD stuff => arith (ADD,add,addi) stuff ! 1803: | AND stuff => arith (AND,and',andi) stuff ! 1804: | OR stuff => arith (OR,or,ori) stuff ! 1805: | XOR stuff => arith (XOR,xor,xori) stuff ! 1806: | SUB (Reg op1, Reg op2, Reg result) => gen1(emit(sub(result,op1,op2))) ! 1807: | MULDIV(DIV, Reg op1, Reg op2) => gen1(emit(div(op1,op2))) ! 1808: | MULDIV(MULT,Reg op1, Reg op2) => gen1(emit(mult(op1,op2))) ! 1809: | MFLO(Reg result) => gen1(emit(mflo(result))) ! 1810: | MFHI(Reg result) => gen1(emit(mfhi(result))) ! 1811: \endcode ! 1812: \begindocs{50} ! 1813: Floating point arithmetic is pretty easy because we always do it in ! 1814: registers. ! 1815: We also support only one format, double precision. ! 1816: \enddocs ! 1817: \begincode{51} ! 1818: \moddef{cases for sizes to be computed}\endmoddef ! 1819: | NEG_D _ => 1 ! 1820: | MUL_D _ => 1 ! 1821: | DIV_D _ => 1 ! 1822: | ADD_D _ => 1 ! 1823: | SUB_D _ => 1 ! 1824: \endcode ! 1825: \begindocs{52} ! 1826: When emitting instructions we have to remember the Mips instructions ! 1827: use result on the left, but the \code{}MIPSCODER\edoc{} signature requires result ! 1828: on the right. ! 1829: \enddocs ! 1830: \begincode{53} ! 1831: \moddef{cases of instructions to be emitted}\endmoddef ! 1832: | NEG_D (Reg op1,Reg result) => gen1(emit(neg_fmt(D_fmt,result,op1))) ! 1833: \endcode ! 1834: \begincode{54} ! 1835: \moddef{functions for emitting instructions}\endmoddef ! 1836: fun float3double instruction (Reg op1,Reg op2,Reg result) = ! 1837: gen1(emit(instruction(D_fmt,result,op1,op2))) ! 1838: \endcode ! 1839: \begincode{55} ! 1840: \moddef{cases of instructions to be emitted}\endmoddef ! 1841: | MUL_D x => float3double mul_fmt x ! 1842: | DIV_D x => float3double div_fmt x ! 1843: | ADD_D x => float3double add_fmt x ! 1844: | SUB_D x => float3double sub_fmt x ! 1845: ! 1846: ! 1847: \endcode ! 1848: \begindocs{56} ! 1849: We offer a separate \code{}MOVE\edoc{} instruction because of large immediate ! 1850: constants. ! 1851: It is always possible to do \code{}move(src,dest)\edoc{} by doing ! 1852: \code{}add(Reg 0,src,dest)\edoc{}, but the general form \code{}add(Reg i, Immed c, dest)\edoc{} ! 1853: takes three instructions when \code{}c\edoc{} is a large constant (more than 16 bits). ! 1854: Rather than clutter up the code for \code{}add\edoc{} (and \code{}or\edoc{} and \code{}xor\edoc{}) by ! 1855: trying to recognize register~0, we provide \code{}move\edoc{} explicitly. ! 1856: ! 1857: \indent \code{}LDI_32\edoc{} takes care of the particular case in which we are ! 1858: loading a 32-bit immediate constant into a register. ! 1859: It dates from the bad old days before \code{}MOVE\edoc{}, and it might be a good idea ! 1860: to remove it sometime. ! 1861: \enddocs ! 1862: \begincode{57} ! 1863: \moddef{functions for emitting instructions}\endmoddef ! 1864: fun domove (Direct (Reg src), Reg dest) = gen1(emit(add(dest,src,0))) ! 1865: | domove (Immed src, Reg dest) = ! 1866: (case size of ! 1867: 1 (* 16 bits *) => gen1(emit(addi(dest,0,src))) ! 1868: | 2 (* 32 bits *) => ! 1869: gen(pos,pcptr,(ref 2, LDI_32(src, Reg dest))::rest) ! 1870: | _ => gen(ErrorMsg.impossible "bad size in domove Immed in mipscoder") ! 1871: ) ! 1872: | domove (Immedlab (ref src), Reg dest) = ! 1873: gen(pos, pcptr, ! 1874: (ref size, ! 1875: ADD(Reg pcreg,Immed(4*(src-(get pcptr))), Reg dest))::rest) ! 1876: \endcode ! 1877: \begindocs{58} ! 1878: Notice we use \code{}easize\edoc{} and not \code{}movesize\edoc{} in the third clause ! 1879: because when we reach this point the treatment of a \code{}MOVE\edoc{} is the same ! 1880: as that of an \code{}ADD\edoc{}. ! 1881: \enddocs ! 1882: \begincode{59} ! 1883: \moddef{functions for computing sizes}\endmoddef ! 1884: fun movesize (Direct _) = 1 ! 1885: | movesize (Immed i) = if abs(i)<32768 then 1 else 2 ! 1886: | movesize (Immedlab(ref lab)) = easize(Immed (4*(lab-(get pcptr)))) ! 1887: ! 1888: \endcode ! 1889: \begincode{60} ! 1890: \moddef{cases for sizes to be computed}\endmoddef ! 1891: | MOVE (src,_) => movesize src ! 1892: | LDI_32 _ => 2 ! 1893: | LUI _ => 1 ! 1894: \endcode ! 1895: \begincode{61} ! 1896: \moddef{cases of instructions to be emitted}\endmoddef ! 1897: | MOVE stuff => domove stuff ! 1898: | LDI_32 (immedconst, Reg dest) => ! 1899: let val (hi,lo) = split immedconst ! 1900: in gen1(emit(lui(dest,hi));emit(addi(dest,dest,lo))) ! 1901: end ! 1902: | LUI (Reg dest,immed16) => gen1(emit(lui(dest,immed16))) ! 1903: ! 1904: \endcode ! 1905: \begindocs{62} ! 1906: ! 1907: Now that we've done arithmetic, we can see how to do control flow without ! 1908: too much trouble. ! 1909: \code{}SLT\edoc{} can be treated just like an arithmetic operator. ! 1910: \code{}BEQ\edoc{} is simple if the address to which we branch is close enough. ! 1911: Otherwise we use the following sequence for \code{}BEQ(Reg op1, Reg op2, ref dest)\edoc{}: ! 1912: \verbatim ! 1913: bne op1,op2,L ! 1914: ADD (Reg pcreg, Immed (4*(dest-pcptr)), Reg tempreg) ! 1915: jr tempreg ! 1916: L: ... ! 1917: \endverbatim ! 1918: Notice we don't have to put a \code{}NOP\edoc{} in the delay slot of the \code{}bne\edoc{}. ! 1919: We don't need one after the jump unless we needed one after the ! 1920: original \code{}BEQ\edoc{}, in which case one will be there. ! 1921: If the branch is taken, we're doing as well as we can. ! 1922: If the branch is not taken, we will have executed an \code{}add\edoc{} or \code{}lui\edoc{} in the ! 1923: delay slot of the \code{}bne\edoc{}, but the results just get thrown away. ! 1924: \enddocs ! 1925: \begincode{63} ! 1926: \moddef{cases for sizes to be computed}\endmoddef ! 1927: | SLT(_, ea, _) => easize ea ! 1928: | BEQ(_,_,_,ref dest) => ! 1929: if abs((pos+1)-dest) < 32768 then 1 (* single instruction *) ! 1930: else 2+easize (Immed (4*(dest-(get pcptr)))) ! 1931: | JUMP _ => 1 ! 1932: | SLT_D _ => 1 ! 1933: | SEQ_D _ => 1 ! 1934: | BCOP1(_,ref dest) => ! 1935: if abs((pos+1)-dest) < 32768 then 1 (* single instruction *) ! 1936: else 2+easize (Immed (4*(dest-(get pcptr)))) ! 1937: | NOP => 1 ! 1938: \endcode ! 1939: \begindocs{64} ! 1940: The implementation is as described, except we use a ! 1941: non-standard \code{}nop\edoc{}. ! 1942: There are many Mips instructions that have no effect, and the standard ! 1943: one is the word with all zeroes (\code{}sll 0,0,0\edoc{}). ! 1944: We use \code{}add\edoc{}, adding 0 to 0 and store the result in 0, because it ! 1945: will be easy to distinguish from a data word that happens to be zero. ! 1946: \enddocs ! 1947: \begincode{65} ! 1948: \moddef{cases of instructions to be emitted}\endmoddef ! 1949: | SLT stuff => arith (SLT,slt,slti) stuff ! 1950: | BEQ(b, Reg op1, Reg op2, ref dest) => ! 1951: if size = 1 then ! 1952: gen1(emit((if b then beq else bne)(op1,op2,dest-(pos+1)))) ! 1953: else gen(pos,pcptr, ! 1954: (ref 1, BEQ(not b, Reg op1, Reg op2, ref(pos+size))) ! 1955: ::(ref (size-2), ! 1956: ADD(Reg pcreg, Immed(4*(dest-(get pcptr))), Reg tempreg)) ! 1957: ::(ref 1, JUMP(Reg tempreg)) ! 1958: ::rest) ! 1959: | JUMP(Reg dest) => gen1(emit(jr(dest))) ! 1960: | SLT_D (Reg op1, Reg op2) => ! 1961: gen1(emit(c_lt(D_fmt,op1,op2))) ! 1962: | SEQ_D (Reg op1, Reg op2) => ! 1963: gen1(emit(c_seq(D_fmt,op1,op2))) ! 1964: | BCOP1(b, ref dest) => ! 1965: let fun bc1f offset = cop1(8,0,offset) ! 1966: fun bc1t offset = cop1(8,1,offset) ! 1967: in if size = 1 then ! 1968: gen1(emit((if b then bc1t else bc1f)(dest-(pos+1)))) ! 1969: else gen(pos,pcptr, ! 1970: (ref 1, BCOP1(not b, ref(pos+size))) ! 1971: ::(ref (size-2), ! 1972: ADD(Reg pcreg, Immed(4*(dest-(get pcptr))), Reg tempreg)) ! 1973: ::(ref 1, JUMP(Reg tempreg)) ! 1974: ::rest) ! 1975: end ! 1976: | NOP => gen1(emit(add(0,0,0))) (* one of the many MIPS no-ops *) ! 1977: \endcode ! 1978: \begindocs{66} ! 1979: ! 1980: Our next problem is to tackle load and store. ! 1981: The major difficulty is if the offset is too large to fit in ! 1982: sixteen bits; if so, we have to create a new base register. ! 1983: If we have \code{}Immedlab\edoc{}, we do it as an offset from \code{}pcreg\edoc{}. ! 1984: \enddocs ! 1985: \begincode{67} ! 1986: \moddef{functions for emitting instructions}\endmoddef ! 1987: fun memop(rform,Reg dest, Direct (Reg base), offset) = ! 1988: (case size ! 1989: of 1 => gen1(emit(rform(dest,offset,base))) ! 1990: | 3 => let val (hi,lo) = split offset ! 1991: in gen1(emit(lui(tempreg,hi)); (* tempreg = hi \LL{} 16 *) ! 1992: emit(add(tempreg,base,tempreg));(* tempreg += base *) ! 1993: emit(rform(dest,lo,tempreg)) (* load dest,lo(tempreg) *) ! 1994: ) ! 1995: end ! 1996: | _ => gen1(ErrorMsg.impossible "bad size in memop Direct in mipscoder") ! 1997: ) ! 1998: | memop(rform,Reg dest, Immed address, offset) = ! 1999: (case size ! 2000: of 1 => gen1(emit(rform(dest,offset+address,0))) ! 2001: | 2 => let val (hi,lo) = split (offset+address) ! 2002: in gen1(emit(lui(tempreg,hi)); ! 2003: emit(rform(dest,lo,tempreg)) ! 2004: ) ! 2005: end ! 2006: | _ => gen1(ErrorMsg.impossible "bad size in memop Immed in mipscoder") ! 2007: ) ! 2008: | memop(rform,Reg dest, Immedlab (ref lab), offset) = ! 2009: memop(rform, Reg dest, Direct (Reg pcreg), offset+4*(lab - get pcptr)) ! 2010: \endcode ! 2011: \begindocs{68} ! 2012: The actual registers don't matter for computing sizes, and in fact ! 2013: the value of \code{}pcreg\edoc{} is not visible here, so we use an arbitrary ! 2014: register (\code{}Reg 0\edoc{}) to compute the size. ! 2015: \enddocs ! 2016: \begincode{69} ! 2017: \moddef{functions for computing sizes}\endmoddef ! 2018: fun adrsize(_, Reg _, Direct _, offset) = ! 2019: if abs(offset)<32768 then 1 else 3 ! 2020: | adrsize(_, Reg _, Immed address, offset) = ! 2021: if abs(address+offset) < 32768 then 1 else 2 ! 2022: | adrsize(x, Reg dest, Immedlab (ref lab), offset) = ! 2023: adrsize(x, Reg dest, Direct (Reg 0 (* pcreg in code *) ), ! 2024: offset+4*(lab-(get pcptr))) ! 2025: \endcode ! 2026: \begincode{70} ! 2027: \moddef{cases for sizes to be computed}\endmoddef ! 2028: | LOAD x => adrsize x ! 2029: | STORE x => adrsize x ! 2030: \endcode ! 2031: \begincode{71} ! 2032: \moddef{cases of instructions to be emitted}\endmoddef ! 2033: | LOAD (Byte,dest,address,offset) => memop(lbu,dest,address,offset) ! 2034: | LOAD (Word,dest,address,offset) => memop(lw,dest,address,offset) ! 2035: | LOAD (Floating,dest,address,offset) => memop(lwc1,dest,address,offset) ! 2036: | STORE (Byte,dest,address,offset) => memop(sb,dest,address,offset) ! 2037: | STORE (Word,dest,address,offset) => memop(sw,dest,address,offset) ! 2038: | STORE (Floating,dest,address,offset) => memop(swc1,dest,address,offset) ! 2039: \endcode ! 2040: \begindocs{72} ! 2041: ! 2042: For the shift instructions, only register and immediate operands ! 2043: make sense. ! 2044: Immediate operands make sense if and only if they are representable ! 2045: in five bits. ! 2046: If everything is right, these are single instructions. ! 2047: \enddocs ! 2048: \begincode{73} ! 2049: \moddef{cases for sizes to be computed}\endmoddef ! 2050: | SLL _ => 1 ! 2051: | SRA _ => 1 ! 2052: \endcode ! 2053: \begincode{74} ! 2054: \moddef{cases of instructions to be emitted}\endmoddef ! 2055: | SLL (Immed shamt, Reg op1, Reg result) => gen1( ! 2056: if (shamt >= 0 andalso shamt < 32) then emit(sll(result,op1,shamt)) ! 2057: else ErrorMsg.impossible ("bad sll shamt " ! 2058: ^ (Integer.makestring shamt) ^ " in mipscoder")) ! 2059: | SLL (Direct(Reg shamt), Reg op1, Reg result) => ! 2060: gen1(emit(sllv(result,op1,shamt))) ! 2061: | SLL (Immedlab _,_,_) => ErrorMsg.impossible "sll shamt is Immedlab in mipscoder" ! 2062: | SRA (Immed shamt, Reg op1, Reg result) => gen1( ! 2063: if (shamt >= 0 andalso shamt < 32) then emit(sra(result,op1,shamt)) ! 2064: else ErrorMsg.impossible ("bad sra shamt " ! 2065: ^ (Integer.makestring shamt) ^ " in mipscoder")) ! 2066: | SRA (Direct(Reg shamt), Reg op1, Reg result) => ! 2067: gen1(emit(srav(result,op1,shamt))) ! 2068: | SRA (Immedlab _,_,_) => ErrorMsg.impossible "sra shamt is Immedlab in mipscoder" ! 2069: \endcode ! 2070: \begindocs{75} ! 2071: ! 2072: Finally, comments are ignored, and marks (backpointers) are written into the ! 2073: instruction stream. ! 2074: ! 2075: Comments are used by the front end to give diagnostics. ! 2076: In the bad old days we would have had two different \code{}MIPSCODER\edoc{}s, one ! 2077: which generated machine code (and ignored comments), and one which ! 2078: wrote out assembly code (and copied comments). ! 2079: Today we have just one, which means the rerouting of comments takes place ! 2080: at a much higher level. Look in \code{}cps/mipsglue.nw\edoc{}. ! 2081: \enddocs ! 2082: \begincode{76} ! 2083: \moddef{cases for sizes to be computed}\endmoddef ! 2084: | COMMENT _ => 0 ! 2085: | MARK => 1 (* backpointer takes one word *) ! 2086: \endcode ! 2087: \begindocs{77} ! 2088: Just for the record, here's the description of what a mark (backpointer) ! 2089: is. ! 2090: ``Take the byte address at which the mark resides and add 4, giving ! 2091: the byte address of the object following the mark. ! 2092: (That object is the marked object.) ! 2093: Subtract the byte address of the initial word that marks the ! 2094: start of this instruction stream. ! 2095: Now divide by 4, giving the distance in words between the ! 2096: beginning of the block and the marked object. ! 2097: Take that quantity and shift it left by multiplying by \code{}power_tags\edoc{}, ! 2098: and indicate the result is a mark by adding the tag bits \code{}tag_backptr\edoc{} ! 2099: into the low order part.'' ! 2100: \code{}pos+1\edoc{} is exactly the required distance in words. ! 2101: \enddocs ! 2102: \begincode{78} ! 2103: \moddef{cases of instructions to be emitted}\endmoddef ! 2104: | COMMENT _ => gen1() ! 2105: | MARK => gen1( ! 2106: let open System.Tags ! 2107: in emitlong((pos+1) * power_tags + tag_backptr) ! 2108: end) ! 2109: \endcode ! 2110: \begindocs{79} ! 2111: ! 2112: \enddocs ! 2113: \begindocs{80} ! 2114: \subsection{Optimization} ! 2115: The first step towards optimization is to take statistics. ! 2116: We will count: \code{}instrs\edoc{}, Mips words, \code{}NOP\edoc{}s in load and branch delays, ! 2117: and \code{}bltzal\edoc{}s. ! 2118: In the current implementation the \code{}bltzal\edoc{}s are implicit, so there ! 2119: is no way to count them or optimize them. ! 2120: \enddocs ! 2121: \begincode{81} ! 2122: \moddef{statistics}\endmoddef ! 2123: fun printstats stream ! 2124: \{inst : int, code : int, data : int, ! 2125: load : int, branch : int, compare : int, size : int\} = ! 2126: let val print = output stream ! 2127: val nop = load+branch+compare ! 2128: val bltzal = size - (code + data) ! 2129: val code = code + bltzal ! 2130: \LA{}definition of \code{}sprintf\edoc{}\RA{} ! 2131: fun P x = substring(makestring(100.0 * x),0,4) (* percent *) ! 2132: fun printf f d = print (sprintf f d) ! 2133: in printf ["Counted "," instrs in "," words (", ! 2134: " code, "," data)\\n" ^ ! 2135: "Used "," NOPs ("," load, "," branch,"," compare) and "," bltzals\\n" ^ ! 2136: "","% of code words were NOPs; ","% were bltzals\\n" ^ ! 2137: "","% of all words were code; ","% of all words were NOPs\\n"] ! 2138: [I inst, I size, I code, I data, ! 2139: I nop, I load, I branch, I compare, I bltzal, ! 2140: P (real nop / real code), P (real bltzal / real code), ! 2141: P (real code / real size), P (real nop / real size)] ! 2142: handle Overflow => print "[Overflow in computing Mips stats]\\n" ! 2143: | Real s => print ("[FPE ("^s^") in computing Mips stats]\\n") ! 2144: end ! 2145: ! 2146: \endcode ! 2147: \begincode{82} ! 2148: \moddef{statistics}\endmoddef ! 2149: \LA{}definition of \code{}iscode\edoc{}\RA{} ! 2150: fun addstats (counts as \{inst,code,data,load,branch,compare\}) = ! 2151: fn nil => counts ! 2152: | (sizeref,first)::(_,NOP)::rest => addstats ! 2153: \{inst=inst+2, code=code+(!sizeref)+1, data=data, ! 2154: load=load+ (case first of LOAD _ => 1 | _ => 0), ! 2155: branch=branch +(case first of BEQ _ => 1 | JUMP _ => 1 ! 2156: | BCOP1 _ => 1 | _ => 0), ! 2157: compare=compare+(case first of SLT_D _ => 1 | SEQ_D _ => 1 ! 2158: | _ => 0) ! 2159: \} rest ! 2160: | (sizeref,first)::rest => addstats ! 2161: \{inst=inst+1, ! 2162: code = code + if iscode(first) then !sizeref else 0, ! 2163: data = data + if not (iscode first) then !sizeref else 0, ! 2164: load=load, ! 2165: branch=branch, ! 2166: compare=compare ! 2167: \} rest ! 2168: ! 2169: ! 2170: fun codestats outfile = ! 2171: let val \{size,stream=instrs\} = prepare (!kept) ! 2172: val zero = \{inst=0, code=0, data=0, load=0, branch=0, compare=0\} ! 2173: val counts as \{inst,code,data,load,branch,compare\} = ! 2174: addstats zero instrs ! 2175: in printstats outfile ! 2176: \{inst=inst,code=code,data=data, ! 2177: load=load,branch=branch,compare=compare,size=size\} ! 2178: end ! 2179: ! 2180: \endcode ! 2181: \begincode{83} ! 2182: \moddef{definition of \code{}iscode\edoc{}}\endmoddef ! 2183: val iscode = fn ! 2184: STRINGCONST _ => false ! 2185: | REALCONST _ => false ! 2186: | EMITLONG _ => false ! 2187: | DEFINE _ => false ! 2188: | EMITLAB _ => false ! 2189: ! 2190: | SLT _ => true ! 2191: | BEQ _ => true ! 2192: | JUMP _ => true ! 2193: | NOP => true ! 2194: | SLT_D _ => true ! 2195: | SEQ_D _ => true ! 2196: | BCOP1 _ => true ! 2197: ! 2198: | ADD _ => true ! 2199: | AND _ => true ! 2200: | OR _ => true ! 2201: | XOR _ => true ! 2202: | SUB _ => true ! 2203: | MULDIV _ => true ! 2204: | MFLO _ => true ! 2205: | MFHI _ => true ! 2206: ! 2207: | NEG_D _ => true ! 2208: | MUL_D _ => true ! 2209: | DIV_D _ => true ! 2210: | ADD_D _ => true ! 2211: | SUB_D _ => true ! 2212: ! 2213: | MOVE _ => true ! 2214: | LDI_32 _ => true ! 2215: | LUI _ => true ! 2216: ! 2217: | LOAD _ => true ! 2218: | STORE _ => true ! 2219: ! 2220: | SLL _ => true ! 2221: | SRA _ => true ! 2222: ! 2223: | COMMENT _ => false ! 2224: | MARK => false ! 2225: ! 2226: \endcode ! 2227: \begincode{84} ! 2228: \moddef{definition of \code{}sprintf\edoc{}}\endmoddef ! 2229: val I = Integer.makestring ! 2230: val R = Real.makestring ! 2231: exception Printf ! 2232: fun sprintf format values = ! 2233: let fun merge([x],nil) = [x] ! 2234: | merge(nil,nil) = nil ! 2235: | merge(x::y,z::w) = x::z:: merge(y,w) ! 2236: | merge _ = raise Printf ! 2237: in implode(merge(format,values)) ! 2238: end ! 2239: ! 2240: \endcode ! 2241: \begindocs{85} ! 2242: ! 2243: At the moment these functions are meaningless junk. ! 2244: \enddocs ! 2245: \begincode{86} ! 2246: \moddef{functions that remove pipeline bubbles}\endmoddef ! 2247: val rec squeeze = ! 2248: ! 2249: fn (x as LOAD(_,Reg d, m, i))::NOP::instr::rest => ! 2250: if use(instr,d) then ?? ! 2251: else squeeze(x::instr::rest) ! 2252: | (x as STORE _)::(y as LOAD _)::rest => ! 2253: x :: squeeze(y::rest) ! 2254: | instr::(x as LOAD(_,Reg d, Direct(Reg s), i))::NOP::rest => ! 2255: if use(instr, d) orelse gen(instr, s) then ?? ! 2256: else squeeze(x::instr::rest) ! 2257: | instr::(x as LOAD(_,Reg d, _, i))::NOP::rest => ! 2258: if use(instr,d) then ?? ! 2259: else squeeze(x::instr::rest) ! 2260: | (x as MFLO _):: (y as MULDIV _) :: rest => ! 2261: x :: squeeze (y::rest) ! 2262: | (x as MFLO(Reg d))::instr::rest => ! 2263: if (use(instr,d) orelse gen(instr,d) then ?? ! 2264: else squeeze(instr::x::rest) ! 2265: | instr :: (x as MULDIV(Reg a, Reg b)) :: rest => ! 2266: if gen(instr,a) orelse gen(instr,b) then ?? ! 2267: else squeeze(x::instr::rest) ! 2268: ! 2269: val rec final = ! 2270: fn ! 2271: | instr::(x as LOAD(_,Reg d, Direct(Reg s), i))::NOP::rest => ! 2272: if gen(instr, s) then instr::final(x::NOP::rest) ! 2273: else x::instr::(final rest) ! 2274: | instr :: (x as JUMP _) :: NOP :: rest => ! 2275: x :: instr :: final rest ! 2276: | instr :: (x as BEQ(_,Reg a, Reg b, _)) :: NOP :: rest => ! 2277: if gen(instr,a) orelse gen(instr,b) then instr::x::NOP::(final rest) ! 2278: else x::instr::(final rest) ! 2279: ! 2280: ! 2281: \endcode ! 2282: \filename{opcodes.nw} ! 2283: \begindocs{0} ! 2284: \chapter{Handling the MIPS opcodes} ! 2285: \section{Introduction} ! 2286: ! 2287: This file generates the code necessary to handle MIPS instructions ! 2288: in a natural, mnemonic way from within ML. ! 2289: All MIPS instructions occupy 32 bits, and since ML has no simple ! 2290: 32~bit data type, we use pairs of integerss to represent MIPS instructions. ! 2291: A pair \code{}(hi,lo)\edoc{} of 16-bit integers holds the most and least significant ! 2292: halfwords of the MIPS word. ! 2293: ML integers are 31 bits, so this is more than adequate. ! 2294: ! 2295: The biggest hassle in converting between these integer pairs and more ! 2296: mnemonic representations is that it is too easy to make mistakes ! 2297: (especially typographical errors) in writing the code. ! 2298: For that reason, I have added an extra level of indirection to the ! 2299: whole business by putting all of the instruction descriptions in ! 2300: tables. ! 2301: These tables are read by an awk script, which writes two ML files: ! 2302: {\tt opcodes.sml} and {\tt mipsdecode.sml}. ! 2303: The {\tt opcodes.sml} file contains the code needed to convert from ! 2304: a mnemonic like \code{}add(3,4,9)\edoc{} (add the contents of register~3 to ! 2305: the contents of register~4, placing the result in register~9) to ! 2306: the integer pair representation of the actual bits in that add instruction ! 2307: (in this case \code{}(137,6176)\edoc{}). ! 2308: The {\tt mipsdecode.sml} file contains a \code{}decode\edoc{} function that converts ! 2309: from the integer pair representation of instructions to a string ! 2310: representation. ! 2311: The string representation is a little hokey at the moment (that is, ! 2312: it's different from the one used in the MIPS book), but it represents ! 2313: a nice compromise between being readable and easy to generate. ! 2314: ! 2315: I have contemplating generating a third file to test the whole ! 2316: business. ! 2317: The idea would be to have a function that would write out (to files) ! 2318: two ! 2319: parallel representations of the same instruction stream (presumably ! 2320: one copy of each known instruction). ! 2321: One representation would be the binary one understood by the MIPS. ! 2322: The other representation would be a string representation. ! 2323: We could then use a tool like {\tt gdb} or {\tt adb} to print out ! 2324: the binary as an instruction sequence (i.e. convert back to ! 2325: a second string representation) and compare the string representations ! 2326: to see if they make sense. ! 2327: ! 2328: \paragraph{Possible bugs} ! 2329: This code should be gone over with care to make sure that negative ! 2330: operands (e.g. in \code{}offset\edoc{}) won't break the code. ! 2331: ! 2332: ! 2333: \enddocs ! 2334: \begindocs{1} ! 2335: ! 2336: We need a special line in the Makefile to handle this file, since ! 2337: it writes both an awk program and that program's input. The input ! 2338: is in module {\tt \LL{}opcodes table\GG{}} so the line is ! 2339: $$\hbox{\code{} $(NOTANGLE) '-Ropcodes table' opcodes.ow > opcodes\edoc{}}$$ ! 2340: The input is nothing but a sequence of tables, each labelled, and ! 2341: processed one after anothing according to the label. ! 2342: The label is always a single word on a line by itself. ! 2343: Tables end with blank lines. ! 2344: \enddocs ! 2345: \begindocs{2} ! 2346: The opcode-to-pair code is written to the standard output, in ! 2347: \code{}structure Opcodes\edoc{}. ! 2348: The pair-to-string code is written to \code{}"mipsdecode.sml"\edoc{}, in ! 2349: \code{}structure MipsDecode\edoc{}. ! 2350: ! 2351: We begin by defining and and shift functions. ! 2352: We make pessimistic assumptions about shifting, trying always to ! 2353: keep the arguments between 0 and 31 inclusive. ! 2354: \enddocs ! 2355: \begincode{3} ! 2356: \moddef{BEGIN}\endmoddef ! 2357: print "structure Opcodes = struct" ! 2358: print "val andb = Bits.andb" ! 2359: print "fun lshift(op1,amt) = " ! 2360: print " if amt<0 then Bits.rshift(op1,0-amt)" ! 2361: print " else Bits.lshift(op1,amt)" ! 2362: print "nonfix sub" # bug fixes; want \code{}sub\edoc{} to be a MIPS opcode ! 2363: print "nonfix div" # bug fixes; want \code{}div\edoc{} to be a MIPS opcode ! 2364: ! 2365: decode = "mipsdecode.sml"; ! 2366: print "structure MipsDecode = struct" > decode ! 2367: print "val andb = Bits.andb" > decode ! 2368: print "fun rshift(op1,amt) = " > decode ! 2369: print " if amt<0 then Bits.lshift(op1,0-amt)" > decode ! 2370: print " else Bits.rshift(op1,amt)" > decode ! 2371: \endcode ! 2372: \begincode{4} ! 2373: \moddef{END}\endmoddef ! 2374: \LA{}write out the definitions of the decoding functions\RA{} ! 2375: print "end (* Opcodes *)" ! 2376: print "end (* Decode *)" > decode ! 2377: \endcode ! 2378: \begindocs{5} ! 2379: The sections BEGIN and END are drawn from ! 2380: our universal model of an awk program: ! 2381: \enddocs ! 2382: \begincode{6} ! 2383: \moddef{*}\endmoddef ! 2384: BEGIN \{ ! 2385: \LA{}BEGIN\RA{} ! 2386: \} ! 2387: \LA{}functions\RA{} ! 2388: \LA{}statements\RA{} ! 2389: END \{ ! 2390: \LA{}END\RA{} ! 2391: \} ! 2392: \endcode ! 2393: \begindocs{7} ! 2394: \section{The opcode tables} ! 2395: The numeric codes for all the MIPS opcodes are described in three ! 2396: tables in the MIPS book on page~A-87. ! 2397: Normal opcodes are six bits, and appear in the \code{}opcode\edoc{} field of the ! 2398: instruction. ! 2399: Two opcodes \code{}special\edoc{} and \code{}bcond\edoc{} stand for several instructions. ! 2400: These instructions are decoded by checking the bit-pattern in the ! 2401: \code{}funct\edoc{} and \code{}cond\edoc{} fields of the instructions, respectively. ! 2402: ! 2403: The tables show which opcodes correspond to which bit-patterns. ! 2404: For example, the \code{}slti\edoc{} corresponds to an \code{}opcode\edoc{} value of octal~12. ! 2405: The table headed \code{}opcode\edoc{} gives the mnemonics for all six-bit patterns ! 2406: in the \code{}opcode\edoc{} field. ! 2407: The \code{}special\edoc{} table shows patterns for the \code{}funct\edoc{} field, used with ! 2408: the \code{}special\edoc{} opcode. ! 2409: The \code{}bcond\edoc{} table shows five-bit patterns for the \code{}cond\edoc{} field, ! 2410: used with the \code{}bcond\edoc{} opcode. ! 2411: In all tables, stars (\code{}*\edoc{}) stand for unused fields. ! 2412: ! 2413: Each table is terminated with a blank line. ! 2414: \enddocs ! 2415: \begincode{8} ! 2416: \moddef{opcodes table}\endmoddef ! 2417: opcode ! 2418: special bcond j jal beq bne blez bgtz ! 2419: addi addiu slti sltiu andi ori xori lui ! 2420: cop0 cop1 cop2 cop3 * * * * ! 2421: * * * * * * * * ! 2422: lb lh lwl lw lbu lhu lwr * ! 2423: sb sh swl sw * * swr * ! 2424: lwc0 lwc1 lwc2 lwc3 * * * * ! 2425: swc0 swc1 swc2 swc3 * * * * ! 2426: ! 2427: special ! 2428: sll * srl sra sllv * srlv srav ! 2429: jr jalr * * syscall break * * ! 2430: mfhi mthi mflo mtlo * * * * ! 2431: mult multu div divu * * * * ! 2432: add addu sub subu and' or xor nor ! 2433: * * slt sltu * * * * ! 2434: * * * * * * * * ! 2435: * * * * * * * * ! 2436: ! 2437: bcond ! 2438: bltz bgez * * * * * * ! 2439: * * * * * * * * ! 2440: bltzal bgezal * * * * * * ! 2441: * * * * * * * * ! 2442: ! 2443: ! 2444: \endcode ! 2445: \begindocs{9} ! 2446: The instructions codes for Coprocessor 1 (floating point) ! 2447: are takin from page B-28 of the Mips book. ! 2448: \enddocs ! 2449: \begincode{10} ! 2450: \moddef{opcodes table}\endmoddef ! 2451: cop1 ! 2452: add_fmt sub_fmt mul_fmt div_fmt * abs_fmt mov_fmt neg_fmt ! 2453: * * * * * * * * ! 2454: * * * * * * * * ! 2455: * * * * * * * * ! 2456: cvt_s cvt_d * * cvt_w * * * ! 2457: * * * * * * * * ! 2458: c_f c_un c_eq c_ueq c_olt c_ult c_ole c_ule ! 2459: c_sf c_ngle c_seq c_ngl c_lt c_nge c_le c_ngt ! 2460: ! 2461: \endcode ! 2462: \begindocs{11} ! 2463: ! 2464: Now we have to deal with reading these tables, and extracting the ! 2465: information stored therein. ! 2466: First of all, for each mnemonic \code{}$i\edoc{} we store the corresponding bit ! 2467: pattern (as an integer, \code{}code\edoc{}) in the array \code{}numberof[$i] \edoc{}. ! 2468: Then, we store the type of the mnemonic (ordinary \code{}OPCODE\edoc{}, ! 2469: \code{}SPECIAL\edoc{}, \code{}BCOND\edoc{}, of \code{}COP1\edoc{}) in the array \code{}typeof[$i] \edoc{}. ! 2470: Finally, we store inverse (a map from type and bit pattern to mnemonic) ! 2471: in the \code{}opcode\edoc{} array. ! 2472: \enddocs ! 2473: \begincode{12} ! 2474: \moddef{store opcode information}\endmoddef ! 2475: if ($i != "*") \{ ! 2476: numberof[$i] = code ! 2477: typeof[$i] = type ! 2478: opcode[type,code] = $i ! 2479: \} else \{ ! 2480: opcode[type,code] = "reserved" ! 2481: \} ! 2482: \endcode ! 2483: \begindocs{13} ! 2484: The types are just constants set at the beginning. ! 2485: \enddocs ! 2486: \begincode{14} ! 2487: \moddef{BEGIN}\endmoddef ! 2488: OPCODE = 1 ; SPECIAL = 2 ; BCOND = 3 ; COP1 = 4 ! 2489: \endcode ! 2490: \begindocs{15} ! 2491: We determine the type by scanning the header word that precedes ! 2492: each table. ! 2493: Once we see the appropriate table header, we set one of \code{}opcodes\edoc{}, ! 2494: \code{}specials\edoc{}, and \code{}bconds\edoc{}, so that determining the type is easy: ! 2495: \enddocs ! 2496: \begincode{16} ! 2497: \moddef{set \code{}type\edoc{}}\endmoddef ! 2498: type = OPCODE * opcodes + SPECIAL * specials + BCOND * bconds + COP1 * cop1s ! 2499: \endcode ! 2500: \begindocs{17} ! 2501: Seeing the right table header causes us to set the right variable. ! 2502: We also remember the line number, because we use the positions of later ! 2503: lines to help extract the bit patterns from the table. ! 2504: \enddocs ! 2505: \begincode{18} ! 2506: \moddef{statements}\endmoddef ! 2507: NF == 1 && $1 == "opcode" \{ ! 2508: startline = NR ! 2509: opcodes = 1 ! 2510: next ! 2511: \} ! 2512: NF == 1 && $1 == "special" \{ ! 2513: startline = NR ! 2514: specials = 1 ! 2515: next ! 2516: \} ! 2517: NF == 1 && $1 == "bcond" \{ ! 2518: startline = NR ! 2519: bconds = 1 ! 2520: next ! 2521: \} ! 2522: NF == 1 && $1 == "cop1" \{ ! 2523: startline = NR ! 2524: cop1s = 1 ! 2525: next ! 2526: \} ! 2527: \endcode ! 2528: \begindocs{19} ! 2529: Any time we see a blank line, that ends the appropriate table. ! 2530: \enddocs ! 2531: \begincode{20} ! 2532: \moddef{statements}\endmoddef ! 2533: NF == 0 \{opcodes = 0; specials = 0; bconds = 0; cop1s = 0 ! 2534: \LA{}blank line resets\RA{} ! 2535: \} ! 2536: \endcode ! 2537: \begindocs{21} ! 2538: Here is the code that actually extracts the bit patterns from ! 2539: the opcode tables. ! 2540: The code is the same for each of the three tables. ! 2541: ! 2542: The \code{}insist_fields(8)\edoc{} issues an error message and returns false (0) ! 2543: unless there are exactly 8 fields on the input line. ! 2544: \enddocs ! 2545: \begincode{22} ! 2546: \moddef{statements}\endmoddef ! 2547: opcodes || specials || bconds || cop1s \{ ! 2548: if (!insist_fields(8)) next ! 2549: \LA{}set \code{}type\edoc{}\RA{} ! 2550: major = NR - startline - 1 # major octal digit from row ! 2551: for (i=1; i<= NF; i++) \{ ! 2552: minor = i-1 # minor octal digit from column ! 2553: code = minor + 8 * major ! 2554: \LA{}store opcode information\RA{} ! 2555: \} ! 2556: \} ! 2557: \endcode ! 2558: \begindocs{23} ! 2559: \section{The instruction fields} ! 2560: Now that we've dealt with the opcodes, we'll handle other fields of ! 2561: the instruction. ! 2562: This table tells us the position of each field within the word, ! 2563: so that if we know a bit-pattern for each field, we can assemble ! 2564: all the fields into an instruction. ! 2565: ! 2566: Not all fields are used in all instructions. ! 2567: Later we'll have a table that indicates exactly which fields are used in ! 2568: which instructions. ! 2569: For now, we just list the fields and their positions with the ! 2570: understanding that some fields will overlap. ! 2571: ! 2572: The table is taken from the MIPS book, page A-3. ! 2573: The numbers are the numbers of the starting and ending bit positions, ! 2574: where 0 is the least and 31 the most significant bit. ! 2575: The names are exactly those used in the book except \code{}op'\edoc{} has been ! 2576: substituted for \code{}op\edoc{} since \code{}op\edoc{} is a reserved word in ML. ! 2577: ! 2578: If a field is signed, we put a \code{}+\edoc{}~sign as the first character ! 2579: of its name. ! 2580: The sign information is used only in decoding (I think). ! 2581: \enddocs ! 2582: \begincode{24} ! 2583: \moddef{opcodes table}\endmoddef ! 2584: fields ! 2585: op' 26 31 ! 2586: rs 21 25 ! 2587: rt 16 20 ! 2588: +immed 0 15 ! 2589: +offset 0 15 ! 2590: base 21 25 ! 2591: target 0 25 ! 2592: rd 11 15 ! 2593: shamt 6 10 ! 2594: funct 0 5 ! 2595: cond 16 20 ! 2596: \LA{}floating point load/store fields\RA{} ! 2597: \LA{}floating point computation fields\RA{} ! 2598: ! 2599: \endcode ! 2600: \begindocs{25} ! 2601: From page B-5. Most fields are the same as the CPU instruction formats. ! 2602: \enddocs ! 2603: \begincode{26} ! 2604: \moddef{floating point load/store fields}\endmoddef ! 2605: ft 16 20 ! 2606: \endcode ! 2607: \begindocs{27} ! 2608: From page B-6. Many fields are reused from earlier specifications. ! 2609: The computational instructions all have a one bit in position 25. ! 2610: Instead of trying to insert special code to handle that, we cheat on ! 2611: it by making that bit part of the format, and cheating on the format. ! 2612: Thus: ! 2613: \enddocs ! 2614: \begincode{28} ! 2615: \moddef{floating point computation fields}\endmoddef ! 2616: fmt 21 25 ! 2617: fs 11 15 ! 2618: fd 6 10 ! 2619: \endcode ! 2620: \begincode{29} ! 2621: \moddef{write format info}\endmoddef ! 2622: print "val S_fmt = 16+0" ! 2623: print "val D_fmt = 16+1" ! 2624: print "val W_fmt = 16+4" ! 2625: ! 2626: \endcode ! 2627: \begindocs{30} ! 2628: The setup for the fields is similar to that used for the opcodes. ! 2629: \enddocs ! 2630: \begincode{31} ! 2631: \moddef{statements}\endmoddef ! 2632: NF == 1 && $1 == "fields" \{ ! 2633: startline = NR ! 2634: fields = 1 ! 2635: \LA{}write format info\RA{} ! 2636: next ! 2637: \} ! 2638: \endcode ! 2639: \begincode{32} ! 2640: \moddef{blank line resets}\endmoddef ! 2641: fields = 0 ! 2642: \endcode ! 2643: \begincode{33} ! 2644: \moddef{statements}\endmoddef ! 2645: fields \{ ! 2646: if (!insist_fields(3)) next ! 2647: fieldname = $1; low = $2; high = $3 ! 2648: \LA{}look for sign in \code{}fieldname\edoc{} and set \code{}signed\edoc{}\RA{} ! 2649: fieldnames[fieldname]= 1 # rememeber all the field names ! 2650: ! 2651: \LA{}write to standard output a function to convert bit-pattern to pair\RA{} ! 2652: \LA{}write to \code{}decode\edoc{} a function to extract field from pair\RA{} ! 2653: ! 2654: \} ! 2655: \endcode ! 2656: \begincode{34} ! 2657: \moddef{look for sign in \code{}fieldname\edoc{} and set \code{}signed\edoc{}}\endmoddef ! 2658: if (substr(fieldname,1,1)=="+") \{ ! 2659: signed = 1 ! 2660: fieldname = substr(fieldname,2) ! 2661: \} else \{ ! 2662: signed = 0 ! 2663: \} ! 2664: \endcode ! 2665: \begindocs{35} ! 2666: ! 2667: The idea is that for each of these fields, we want to write a function ! 2668: that will take an integer argument and shift it by the right amount. ! 2669: Since we have to represent the 32-bit quantities as pairs of integers, ! 2670: we actually use two functions, one for the high half and one for the low. ! 2671: So, for example, for the \code{}rd\edoc{} field we will produce two function definitions, ! 2672: \code{}rdHI\edoc{} and \code{}rdLO\edoc{}. ! 2673: ! 2674: The awk function \code{}function_definition\edoc{} is used to compute ML function ! 2675: definitions. ! 2676: It takes as arguments the name of the function and the number of arguments ! 2677: to that function. ! 2678: The arguments are numbered \code{}A1\edoc{}, \code{}A2\edoc{}, et cetera. ! 2679: ! 2680: The functions themselves are all tedious combinations of ands and shifts. ! 2681: At one time I had convinced myself that this worked. ! 2682: \enddocs ! 2683: \begincode{36} ! 2684: \moddef{write to standard output a function to convert bit-pattern to pair}\endmoddef ! 2685: if (low >= 16) \{ ! 2686: printf "%s", function_definition(fieldname "LO",1); print "0" ! 2687: \} else \{ ! 2688: printf "%s", function_definition(fieldname "LO",1) ! 2689: printf "andb(lshift(A1,%d),65535)\\n", low ! 2690: \} ! 2691: if (high < 16) \{ ! 2692: printf "%s", function_definition(fieldname "HI",1); print "0" ! 2693: \} else \{ ! 2694: printf "%s", function_definition(fieldname "HI",1) ! 2695: printf "lshift(A1,%s)\\n", mlnumber(low - 16) ! 2696: \} ! 2697: \endcode ! 2698: \begindocs{37} ! 2699: The inverse operation is ! 2700: to extract a bit pattern from a pair. ! 2701: We'll want that if we ever care to decode instructions. ! 2702: This time, the function to extract e.g.\ field \code{}rd\edoc{} from a pair ! 2703: is the function \code{}THErd\edoc{} applied to that pair. ! 2704: ! 2705: The functions work first by extracting from the low part, then ! 2706: from the high part, and adding everything together. ! 2707: If the field is signed, we make the value negative if it is too high. ! 2708: \enddocs ! 2709: \begincode{38} ! 2710: \moddef{write to \code{}decode\edoc{} a function to extract field from pair}\endmoddef ! 2711: printf "%s", function_definition("THE" fieldname,2) > decode ! 2712: if (signed) printf "let val n = " > decode ! 2713: \LA{}print expression for unsigned value\RA{} ! 2714: if (signed) \{ ! 2715: printf "in if n < %d then n else n - %d\\nend\\n", ! 2716: 2**(high-low), 2**(high-low+1) > decode ! 2717: \} ! 2718: ! 2719: \endcode ! 2720: \begincode{39} ! 2721: \moddef{print expression for unsigned value}\endmoddef ! 2722: if (low >= 16) \{ ! 2723: printf "0" > decode ! 2724: \} else \{ ! 2725: printf "andb(rshift(A2,%d),%d)", low, ! 2726: (2**(min(15,high)-low+1)-1) > decode ! 2727: \} ! 2728: printf " + " > decode ! 2729: if (high < 16) \{ ! 2730: printf "0\\n" > decode ! 2731: \} else \{ ! 2732: printf "rshift(andb(A1,%d),%s)\\n", (2**(high-16+1)-1), ! 2733: mlnumber(low - 16) > decode ! 2734: \} ! 2735: \endcode ! 2736: \begindocs{40} ! 2737: ML uses a strange minus sign (\code{}~\edoc{} instead of \code{}-\edoc{}), ! 2738: so we print numbers that might be negative like this: ! 2739: \enddocs ! 2740: \begincode{41} ! 2741: \moddef{functions}\endmoddef ! 2742: function mlnumber(n, s) \{ ! 2743: if (n<0) s = sprintf("~%d", -n) ! 2744: else s = sprintf("%d", n) ! 2745: return s ! 2746: \} ! 2747: \endcode ! 2748: \begindocs{42} ! 2749: For reasons best known to its designers, awk has no \code{}min\edoc{} function. ! 2750: \enddocs ! 2751: \begincode{43} ! 2752: \moddef{functions}\endmoddef ! 2753: function min(x,y)\{ ! 2754: if (x<y) return x ! 2755: else return y ! 2756: \} ! 2757: \endcode ! 2758: \begindocs{44} ! 2759: \section{The list of instructions and their formats} ! 2760: This is the section that tells which fields are used in what instructions, ! 2761: and in what order the fields appear. ! 2762: The information is from Appendix A ! 2763: of the MIPS book and should be proofread. ! 2764: ! 2765: To cut down on the number of ML functions generated, we can comment out ! 2766: instructions with a \code{}#\edoc{} in the first column. ! 2767: This means that no code will be generated for the instruction, and ! 2768: it won't appear in the \code{}structure Opcodes\edoc{}. ! 2769: \enddocs ! 2770: \begincode{45} ! 2771: \moddef{opcodes table}\endmoddef ! 2772: instructions ! 2773: add rd rs rt ! 2774: addi rt rs immed ! 2775: addiu rt rs immed ! 2776: addu rd rs rt ! 2777: and' rd rs rt ! 2778: andi rt rs immed ! 2779: beq rs rt offset ! 2780: bgez rs offset ! 2781: bgezal rs offset ! 2782: bgtz rs offset ! 2783: blez rs offset ! 2784: bltz rs offset ! 2785: bltzal rs offset ! 2786: bne rs rt offset ! 2787: break ! 2788: div rs rt ! 2789: divu rs rt ! 2790: j target ! 2791: jal target ! 2792: jalr rs rd ! 2793: jr rs ! 2794: lb rt offset base ! 2795: lbu rt offset base ! 2796: lh rt offset base ! 2797: lb rt offset base ! 2798: lhu rt offset base ! 2799: lui rt immed ! 2800: lw rt offset base ! 2801: lwl rt offset base ! 2802: lwr rt offset base ! 2803: mfhi rd ! 2804: mflo rd ! 2805: mthi rs ! 2806: mtlo rs ! 2807: mult rs rt ! 2808: multu rs rt ! 2809: nor rd rs rt ! 2810: or rd rs rt ! 2811: ori rt rs immed ! 2812: sb rt offset base ! 2813: sh rt offset base ! 2814: sll rd rt shamt ! 2815: sllv rd rt rs ! 2816: slt rd rs rt ! 2817: slti rt rs immed ! 2818: sltiu rt rs immed ! 2819: sltu rd rs rt ! 2820: sra rd rt shamt ! 2821: srav rd rt rs ! 2822: srl rd rt shamt ! 2823: srlv rd rt rs ! 2824: sub rd rs rt ! 2825: subu rd rs rt ! 2826: sw rt offset base ! 2827: swl rt offset base ! 2828: swr rt offset base ! 2829: syscall ! 2830: xor rd rs rt ! 2831: xori rt rs immed ! 2832: \LA{}floating point instructions\RA{} ! 2833: ! 2834: ! 2835: \endcode ! 2836: \begindocs{46} ! 2837: We define only those floating point instructions we seem likely to need. ! 2838: To distinguish them as floating point we append an f to their names. ! 2839: \enddocs ! 2840: \begincode{47} ! 2841: \moddef{floating point instructions}\endmoddef ! 2842: add_fmt fmt fd fs ft ! 2843: div_fmt fmt fd fs ft ! 2844: lwc1 ft offset base ! 2845: mul_fmt fmt fd fs ft ! 2846: neg_fmt fmt fd fs ! 2847: sub_fmt fmt fd fs ft ! 2848: swc1 ft offset base ! 2849: c_seq fmt fs ft ! 2850: c_lt fmt fs ft ! 2851: \endcode ! 2852: \begindocs{48} ! 2853: ! 2854: Here is a terrible hack to enable us to construct branch on coprocessor~1 ! 2855: true or false. ! 2856: We will use \code{}fun bc1f offset = cop1(0,offset)\edoc{} and ! 2857: \code{}fun bc1t offset = cop1(1,offset)\edoc{}. ! 2858: \enddocs ! 2859: \begincode{49} ! 2860: \moddef{floating point instructions}\endmoddef ! 2861: cop1 rs rt offset ! 2862: \endcode ! 2863: \begindocs{50} ! 2864: ! 2865: ! 2866: ! 2867: \enddocs ! 2868: \begindocs{51} ! 2869: For each instruction, we define an ML function with the appropriate ! 2870: number of arguments. ! 2871: When that function is given an integer in each argument, ! 2872: it converts the whole thing to one MIPS instruction, represented as an ! 2873: integer pair. ! 2874: ! 2875: The implementation is a bit of a grubby mess. ! 2876: Doing the fields is straightforward enough, but ! 2877: for each mnemonic we have to do something different based ! 2878: on its type, because each type of opcode goes in a different ! 2879: field. ! 2880: Moreover, for mnemonics of type \code{}SPECIAL\edoc{}, \code{}BCOND\edoc{}, and \code{}COP1\edoc{} we ! 2881: have to generate \code{}special\edoc{}, \code{}bcond\edoc{}, and \code{}cop1\edoc{} in the \code{}op'\edoc{} field. ! 2882: Finally, we have to do it all twice; once for the high order ! 2883: halfword and once for the low order halfword. ! 2884: \enddocs ! 2885: \begincode{52} ! 2886: \moddef{compute function that generates this instruction}\endmoddef ! 2887: printf "%s", function_definition(opname, NF-1) ! 2888: printf "(" # open parenthesis for pair ! 2889: for (i=2; i<= NF; i++) \{ ! 2890: if (!($i in fieldnames)) \LA{}bad field name\RA{} ! 2891: printf "%sHI(A%d)+", $i, i-1 ! 2892: \} ! 2893: if (typeof[opname]==OPCODE) \{ ! 2894: printf "op'HI(%d)", numberof[opname] ! 2895: \} else if (typeof[opname]==SPECIAL) \{ ! 2896: printf "op'HI(%d)+", numberof["special"] ! 2897: printf "functHI(%d)", numberof[opname] ! 2898: \} else if (typeof[opname]==BCOND) \{ ! 2899: printf "op'HI(%d)+", numberof["bcond"] ! 2900: printf "condHI(%d)", numberof[opname] ! 2901: \} else if (typeof[opname]==COP1) \{ ! 2902: printf "op'HI(%d)+", numberof["cop1"] ! 2903: printf "functHI(%d)", numberof[opname] ! 2904: \} else \LA{}bad operator name\RA{} ! 2905: printf ", " ! 2906: for (i=2; i<= NF; i++) \{ ! 2907: if (!($i in fieldnames)) \LA{}bad field name\RA{} ! 2908: printf "%sLO(A%d)+", $i, i-1 ! 2909: \} ! 2910: if (typeof[opname]==OPCODE) \{ ! 2911: printf "op'LO(%d)", numberof[opname] ! 2912: \} else if (typeof[opname]==SPECIAL) \{ ! 2913: printf "op'LO(%d)+", numberof["special"] ! 2914: printf "functLO(%d)", numberof[opname] ! 2915: \} else if (typeof[opname]==BCOND) \{ ! 2916: printf "op'LO(%d)+", numberof["bcond"] ! 2917: printf "condLO(%d)", numberof[opname] ! 2918: \} else if (typeof[opname]==COP1) \{ ! 2919: printf "op'LO(%d)+", numberof["cop1"] ! 2920: printf "functLO(%d)", numberof[opname] ! 2921: \} else \LA{}bad operator name\RA{} ! 2922: printf ")\\n" ! 2923: \endcode ! 2924: \begindocs{53} ! 2925: ! 2926: Setup is as before. ! 2927: \enddocs ! 2928: \begincode{54} ! 2929: \moddef{statements}\endmoddef ! 2930: NF == 1 && $1 == "instructions" \{ ! 2931: startline = NR ! 2932: instructions = 1 ! 2933: next ! 2934: \} ! 2935: \endcode ! 2936: \begincode{55} ! 2937: \moddef{blank line resets}\endmoddef ! 2938: instructions= 0 ! 2939: \endcode ! 2940: \begincode{56} ! 2941: \moddef{statements}\endmoddef ! 2942: instructions && $0 !~ /^#/ \{ ! 2943: opname = $1 ! 2944: ! 2945: \LA{}compute string displayed when this instruction is decoded\RA{} ! 2946: ######## gsub("[^a-z']+"," ") ### ill-advised ! 2947: ! 2948: \LA{}compute function that generates this instruction\RA{} ! 2949: \} ! 2950: ! 2951: \endcode ! 2952: \begindocs{57} ! 2953: \paragraph{Decoding instructions} ! 2954: When we've decoded an instruction, we have to display some sort of ! 2955: string representation that tells us what the instruction is. ! 2956: Ideally we should display either just what the assembler expects, ! 2957: or perhaps just what dbx displays when asked about actual instructions ! 2958: in memory images. ! 2959: ! 2960: For now, we just give the mnemonic for the instruction, followed ! 2961: by a description of each field (followed by a newline). ! 2962: The fields are described as name-value pairs. ! 2963: ! 2964: We rely on the fact that for a field e.g.\ \code{}rd\edoc{}, the string ! 2965: representation of the value of that field is in \code{}Srd\edoc{}. ! 2966: \enddocs ! 2967: \begincode{58} ! 2968: \moddef{compute string displayed when this instruction is decoded}\endmoddef ! 2969: temp = "\\"" opname " \\"" ! 2970: for (i=2; i<=NF; i++) \{ ! 2971: temp = sprintf( "%s ^ \\"%s = \\" ^ S%s", temp, $i, $i) ! 2972: if (i<NF) temp = sprintf("%s ^ \\",\\" ", temp) ! 2973: \} ! 2974: displayof[opname]=temp " ^ \\"\\\\n\\"" ! 2975: ! 2976: \endcode ! 2977: \begindocs{59} ! 2978: The implementation of the decoding function is split into several parts. ! 2979: First, we have to be able to extract any field from an instruction. ! 2980: Then, we have to be able to decode four kinds of opcodes: ! 2981: \code{}OPCODE\edoc{}s, \code{}BCOND\edoc{}s, \code{}SPECIAL\edoc{}s, and \code{}COP1\edoc{}s. ! 2982: The main function is the one that does ordinary opcodes. ! 2983: The others are auxiliary. ! 2984: \enddocs ! 2985: \begincode{60} ! 2986: \moddef{write out the definitions of the decoding functions}\endmoddef ! 2987: printf "%s", function_definition("decode",2) > decode ! 2988: print "let" > decode ! 2989: \LA{}write definitions of integer and string representations of each field\RA{} ! 2990: \LA{}write expression that decodes the \code{}funct\edoc{} field for \code{}special\edoc{}s\RA{} ! 2991: \LA{}write expression that decodes the \code{}cond\edoc{} field for \code{}bcond\edoc{}s\RA{} ! 2992: \LA{}write expression that decodes the \code{}funct\edoc{} field for \code{}cop1\edoc{}s\RA{} ! 2993: print "in" > decode ! 2994: \LA{}write \code{}case\edoc{} expression that decodes the \code{}op'\edoc{} field for each instruction\RA{} ! 2995: print "end" > decode ! 2996: \endcode ! 2997: \begindocs{61} ! 2998: We give each field its own name for an integer version, and its name ! 2999: preceded by \code{}S\edoc{} for its string version. ! 3000: These values are all computed just once, from the arguments to the ! 3001: enclosing function (\code{}decode\edoc{}). ! 3002: \enddocs ! 3003: \begincode{62} ! 3004: \moddef{write definitions of integer and string representations of each field}\endmoddef ! 3005: for (f in fieldnames) \{ ! 3006: printf "val %s = THE%s(A1,A2)\\n", f, f > decode ! 3007: printf "val S%s = Integer.makestring %s\\n", f, f > decode ! 3008: \} ! 3009: \endcode ! 3010: \begindocs{63} ! 3011: The next three functions are very much of a piece. ! 3012: They are just enormous \code{}case\edoc{} expressions that match up integers ! 3013: (bit patterns) to strings. ! 3014: The fundamental operation is printing out a decimal value and a string ! 3015: for each opcode: ! 3016: \enddocs ! 3017: \begincode{64} ! 3018: \moddef{if \code{}name\edoc{} is known, display a case for it}\endmoddef ! 3019: if (name != "" && name != "reserved") \{ ! 3020: \LA{}print space or bar (\code{}|\edoc{})\RA{} ! 3021: disp = displayof[name] ! 3022: if (disp=="") disp="\\"" name "(??? unknown format???)\\\\n\\"" ! 3023: printf "%d => %s\\n", code, disp > decode ! 3024: \} ! 3025: \endcode ! 3026: \begindocs{65} ! 3027: Cases must be separated by vertical bars. ! 3028: We do the separation by putting a vertical bar before each case except ! 3029: the first. ! 3030: We use a hack to discover the first; we assume that code~0 is always ! 3031: defined, and so it will always be the first. ! 3032: \enddocs ! 3033: \begincode{66} ! 3034: \moddef{print space or bar (\code{}|\edoc{})}\endmoddef ! 3035: if (code!=0) printf " | " > decode # hack but it works ! 3036: else printf " " > decode ! 3037: \endcode ! 3038: \begincode{67} ! 3039: \moddef{write expression that decodes the \code{}funct\edoc{} field for \code{}special\edoc{}s}\endmoddef ! 3040: print "val do_special =" > decode ! 3041: print "(case funct of" > decode ! 3042: for (code=0; code<256; code++) \{ ! 3043: name = opcode[SPECIAL,code] ! 3044: \LA{}if \code{}name\edoc{} is known, display a case for it\RA{} ! 3045: \} ! 3046: printf " | _ => \\"unknown special\\\\n\\"\\n" > decode ! 3047: print " ) " > decode ! 3048: \endcode ! 3049: \begincode{68} ! 3050: \moddef{write expression that decodes the \code{}cond\edoc{} field for \code{}bcond\edoc{}s}\endmoddef ! 3051: print "val do_bcond =" > decode ! 3052: print "(case cond of" > decode ! 3053: for (code=0; code<256; code++) \{ ! 3054: name = opcode[BCOND,code] ! 3055: \LA{}if \code{}name\edoc{} is known, display a case for it\RA{} ! 3056: \} ! 3057: printf " | _ => \\"unknown bcond\\\\n\\"\\n" > decode ! 3058: print " ) " > decode ! 3059: \endcode ! 3060: \begincode{69} ! 3061: \moddef{write expression that decodes the \code{}funct\edoc{} field for \code{}cop1\edoc{}s}\endmoddef ! 3062: print "val do_cop1 =" > decode ! 3063: print "(case funct of" > decode ! 3064: for (code=0; code<256; code++) \{ ! 3065: name = opcode[COP1,code] ! 3066: \LA{}if \code{}name\edoc{} is known, display a case for it\RA{} ! 3067: \} ! 3068: printf " | _ => \\"unknown cop1\\\\n\\"\\n" > decode ! 3069: print " ) " > decode ! 3070: \endcode ! 3071: \begindocs{70} ! 3072: The major expression is a little more complicated, because it has to ! 3073: check for \code{}special\edoc{}, \code{}bcond\edoc{}, and \code{}cop1\edoc{} and handle those separately. ! 3074: \enddocs ! 3075: \begincode{71} ! 3076: \moddef{write \code{}case\edoc{} expression that decodes the \code{}op'\edoc{} field for each instruction}\endmoddef ! 3077: print "(case op' of" > decode ! 3078: for (code=0; code<256; code++) \{ ! 3079: name = opcode[OPCODE,code] ! 3080: if (name=="special") \{ ! 3081: \LA{}print space or bar (\code{}|\edoc{})\RA{} ! 3082: printf "%d => %s\\n", code, "do_special" > decode ! 3083: \} else if (name=="bcond") \{ ! 3084: \LA{}print space or bar (\code{}|\edoc{})\RA{} ! 3085: printf "%d => %s\\n", code, "do_bcond" > decode ! 3086: \} else if (name=="cop1") \{ ! 3087: \LA{}print space or bar (\code{}|\edoc{})\RA{} ! 3088: printf "%d => %s\\n", code, "do_cop1" > decode ! 3089: \} else \LA{}if \code{}name\edoc{} is known, display a case for it\RA{} ! 3090: \} ! 3091: printf " | _ => \\"unknown opcode\\\\n\\"\\n" > decode ! 3092: print " ) " > decode ! 3093: \endcode ! 3094: \begindocs{72} ! 3095: \section{testing} ! 3096: One day someone will have to modify the instruction handler so that ! 3097: it generates a test invocation of each instruction. ! 3098: Then the results can be handed to something like adb or dbx and we can ! 3099: see whether the system agrees with us about what we're generating. ! 3100: ! 3101: \enddocs ! 3102: \begindocs{73} ! 3103: \section{Defining ML functions} ! 3104: The awk function \code{}function_definition\edoc{} is used to ! 3105: come up with ML function definitions. ! 3106: It takes as arguments the name of the function and the number of arguments ! 3107: to that function, and returns a string containing the initial part of ! 3108: the function definition. ! 3109: Writing an expression following that string will result in a complete ! 3110: ML function. ! 3111: ! 3112: If we ever wanted to define these things as C preprocessor macros instead, ! 3113: we could do it by substituting \code{}macro_definition\edoc{}. ! 3114: I'm not sure it would ever make sense to do so, but I'm leaving the ! 3115: code here anyway. ! 3116: \enddocs ! 3117: \begincode{74} ! 3118: \moddef{functions}\endmoddef ! 3119: function function_definition(name, argc, i, temp) \{ ! 3120: if (argc==0) \{ ! 3121: temp = sprintf("val %s = ", name) ! 3122: \} else \{ ! 3123: temp = sprintf( "fun %s(", name) ! 3124: for (i=1; i< argc; i++) temp = sprintf("%sA%d,", temp,i) ! 3125: temp = sprintf( "%sA%d) = ", temp, argc) ! 3126: \} ! 3127: return temp ! 3128: \} ! 3129: \endcode ! 3130: \begincode{75} ! 3131: \moddef{useless functions}\endmoddef ! 3132: function macro_definition(name, argc, i, temp) \{ ! 3133: if (argc==0) \{ ! 3134: temp = sprintf("#define %s ", name) ! 3135: \} else \{ ! 3136: temp = sprintf( "#define %s(", name) ! 3137: for (i=1; i< argc; i++) temp = sprintf("%sA%d,", temp,i) ! 3138: temp = sprintf( "%sA%d) ", temp, argc) ! 3139: \} ! 3140: return temp ! 3141: \} ! 3142: \endcode ! 3143: \begindocs{76} ! 3144: \section{Handling error conditions} ! 3145: Here are a bunch of uninteresting functions and modules ! 3146: that handle error conditions. ! 3147: \enddocs ! 3148: \begincode{77} ! 3149: \moddef{bad operator name}\endmoddef ! 3150: \{ ! 3151: print "unknown opcode", opname, "on line", NR > stderr ! 3152: next ! 3153: \} ! 3154: \endcode ! 3155: \begincode{78} ! 3156: \moddef{bad field name}\endmoddef ! 3157: \{ ! 3158: print "unknown field", $i, "on line", NR > stderr ! 3159: next ! 3160: \} ! 3161: \endcode ! 3162: \begincode{79} ! 3163: \moddef{BEGIN}\endmoddef ! 3164: stderr="/dev/tty" ! 3165: \endcode ! 3166: \begincode{80} ! 3167: \moddef{functions}\endmoddef ! 3168: function insist_fields(n) \{ ! 3169: if (NF != n) \{ ! 3170: print "Must have", n, "fields on line",NR ":", $0 > stderr ! 3171: return 0 ! 3172: \} else \{ ! 3173: return 1 ! 3174: \} ! 3175: \} ! 3176: \endcode ! 3177: \begindocs{81} ! 3178: \section{Leftover junk} ! 3179: Like a pack rat, I never throw out anything that might be useful again later. ! 3180: \enddocs ! 3181: \begincode{82} ! 3182: \moddef{junk}\endmoddef ! 3183: function thetype(n) \{ ! 3184: if (n==OPCODE) return "OPCODE" ! 3185: else if (n==SPECIAL) return "SPECIAL" ! 3186: else if (n==BCOND) return "BCOND" ! 3187: else if (n==COP1) return "COP1" ! 3188: else return "BADTYPE" ! 3189: \} ! 3190: \endcode ! 3191: \begincode{83} ! 3192: \moddef{decoding junk}\endmoddef ! 3193: for (f in fieldnames) \{ ! 3194: printf "^ \\"\\\\n%s = \\" ^ Integer.makestring %s\\n",f,f > decode ! 3195: \} ! 3196: printf "^\\"\\\\n\\"\\n" > decode ! 3197: \endcode ! 3198: \filename{/u/nr/sml/36/src/runtime/MIPS.prim.nw} ! 3199: \begindocs{0} ! 3200: \section{Assembly-language primitives for the run-time system} ! 3201: This file is derived from the similar file for the VAX. ! 3202: We include \code{}<regdef.h>\edoc{}, which defines names for the registers. ! 3203: \enddocs ! 3204: \begincode{1} ! 3205: \moddef{*}\endmoddef ! 3206: #include "tags.h" ! 3207: #include "prof.h" ! 3208: #include "ml.h" ! 3209: #include "prim.h" ! 3210: \LA{}register definitions\RA{} ! 3211: \LA{}\code{}String\edoc{} and \code{}Closure\edoc{} definitions\RA{} ! 3212: .data ! 3213: \LA{}data segment items\RA{} ! 3214: .text ! 3215: \LA{}run vector\RA{} ! 3216: \LA{}array\RA{} ! 3217: \LA{}string and bytearray\RA{} ! 3218: \LA{}C linkage\RA{} ! 3219: \LA{}calling C routines\RA{} ! 3220: \LA{}system calls\RA{} ! 3221: \LA{}floating point\RA{} ! 3222: /* this bogosity is for export.c */ ! 3223: .globl startptr ! 3224: startptr: .word __start /* just a guess... */ ! 3225: ! 3226: ! 3227: \endcode ! 3228: \begindocs{2} ! 3229: We define a couple of macros for creating strings and closures. ! 3230: When calling \code{}String\edoc{} we should use a literal string whose length ! 3231: is a multiple of~4. ! 3232: ! 3233: The closure of a primitive function ! 3234: is a record of length~1, containing a pointer to the first ! 3235: instruction in the function. ! 3236: All closures have length~1 because there aren't any free variables in any ! 3237: of the primitive functions. ! 3238: \enddocs ! 3239: \begincode{3} ! 3240: \moddef{\code{}String\edoc{} and \code{}Closure\edoc{} definitions}\endmoddef ! 3241: #define String(handle,len,str) .align 2;\\ ! 3242: .set noreorder;\\ ! 3243: .word len*power_tags+tag_string;\\ ! 3244: handle: .ascii str;\\ ! 3245: .set reorder ! 3246: #define Closure(name) .align 2;\\ ! 3247: .set noreorder;\\ ! 3248: .word mak_desc(1,tag_record);\\ ! 3249: name: .word 9f; /* address of routine */ \\ ! 3250: .word 1; /* here for historical reasons */\\ ! 3251: .word tag_backptr;\\ ! 3252: .set reorder;\\ ! 3253: 9: ! 3254: \endcode ! 3255: \begindocs{4} ! 3256: \subsection{Allocation and garbage collection} ! 3257: Put a brief summary here: gc is caused by storing beyond the end of high ! 3258: memory. ! 3259: For that reason we store the last word of objects first. ! 3260: ! 3261: \enddocs ! 3262: \begindocs{5} ! 3263: \subsection{Register usage} ! 3264: \input regs ! 3265: \enddocs ! 3266: \begincode{6} ! 3267: \moddef{register definitions}\endmoddef ! 3268: #define stdarg 2 ! 3269: #define stdcont 3 ! 3270: #define stdclos 4 ! 3271: #define storeptr 22 ! 3272: #define dataptr 23 ! 3273: #define exnptr 30 ! 3274: #define artemp1 24 ! 3275: #define artemp2 25 ! 3276: #define artemp3 20 ! 3277: #define ptrtemp 21 ! 3278: \endcode ! 3279: \begindocs{7} ! 3280: The MIPS version of Unix doesn't put underscores in front of global names. ! 3281: ! 3282: First we define the global \code{}runvec\edoc{}. ! 3283: This is an Ml object that represents the substructure \code{}A\edoc{} in ! 3284: {\tt boot/assembly.sig}. ! 3285: All the ML functions will call these primitives by grabbing them ! 3286: out of this record, which contains pointers to all the primitives. ! 3287: \enddocs ! 3288: \begincode{8} ! 3289: \moddef{run vector}\endmoddef ! 3290: ! 3291: .globl runvec ! 3292: .align 2 ! 3293: .word mak_desc(8,tag_record) ! 3294: runvec: ! 3295: .word array_v ! 3296: .word callc_v ! 3297: .word create_b_v ! 3298: .word create_s_v ! 3299: .word floor_v ! 3300: .word logb_v ! 3301: .word scalb_v ! 3302: .word syscall_v ! 3303: ! 3304: \endcode ! 3305: \begindocs{9} ! 3306: \subsection{Creating arrays, strings, and bytearrays} ! 3307: \code{}array(m,x)\edoc{} creates an array of length $n$, each element initialized ! 3308: to $x$. ! 3309: (The corresponding record creation code is not implemented as a primitive; ! 3310: the ML compiler generates that code in line.) ! 3311: $n$~is a tagged integer representing the length in words; ! 3312: $x$ can be any value. ! 3313: This routine will loop forever (or until something strange happens ! 3314: in memory) if $n<0$. ! 3315: ! 3316: We need to be careful in the implementation to make sure all register values ! 3317: are sensible when garbage collection might occur. ! 3318: ! 3319: If the order of instructions seems a little strange, it's because we try to ! 3320: make sensible use of load delay slots. ! 3321: \enddocs ! 3322: \begincode{10} ! 3323: \moddef{array}\endmoddef ! 3324: Closure(array_v) ! 3325: lw $artemp1,0($stdarg) /* tagged length in $artemp1 */ ! 3326: lw $10,4($stdarg) /* get initial value in $10 */ ! 3327: sra $artemp1,1 /* drop the tag bit */ ! 3328: sll $artemp2,$artemp1,width_tags /* length for descr into $artemp2 */ ! 3329: ori $artemp2,tag_array /* complete descriptor into $artemp2 */ ! 3330: sll $artemp1,2 /* get length in bytes into $artemp1 */ ! 3331: .set noreorder /* can't reorder because collection might occur */ ! 3332: add $artemp3,$artemp1,$dataptr /* $artemp3 points to last word ! 3333: of new array*/ ! 3334: badgc1: sw $0,($artemp3) /* clear; causes allocation */ ! 3335: .set reorder /* can rearrange instructions again */ ! 3336: \endcode ! 3337: \begincode{11} ! 3338: \moddef{load bad pc into \code{}$artemp2\edoc{}; branch to \code{}badpc\edoc{} if == \code{}$artemp1\edoc{}}\endmoddef ! 3339: la $artemp2,badgc1 ! 3340: beq $artemp1,$artemp2,badpc ! 3341: \endcode ! 3342: \begindocs{12} ! 3343: At this point garbage collection may have occurred. ! 3344: Ordinarily, we couldn't rely ! 3345: on the value in \code{}$artemp3\edoc{}, because it's not forwarded. ! 3346: However, this is one of the special garbage collection locations, ! 3347: so we do know that \code{}$artemp3\edoc{} is sensible. ! 3348: But, since we really want something larger, we recompute it, ! 3349: using the (possibly changed) value of the data pointer. ! 3350: Extra cleverness here might enable us to save one instruction. ! 3351: \enddocs ! 3352: \begincode{13} ! 3353: \moddef{array}\endmoddef ! 3354: sw $artemp2,0($dataptr) /* store the descriptor */ ! 3355: add $dataptr,4 /* points to new object */ ! 3356: add $artemp3,$artemp1,$dataptr /* beyond last word of new array*/ ! 3357: add $stdarg,$dataptr,$0 /* put ptr in return register ! 3358: (return val = arg of continuation) */ ! 3359: \LA{}store the initial value in every slot, leaving \code{}$dataptr\edoc{} pointing to the first free word\RA{} ! 3360: lw $10,0($stdcont) /* grab continuation */ ! 3361: j $10 /* return */ ! 3362: ! 3363: \endcode ! 3364: \begindocs{14} ! 3365: With some clever thinking, the size of this loop could probably be cut ! 3366: from four instructions to three instructions. ! 3367: \enddocs ! 3368: \begincode{15} ! 3369: \moddef{store the initial value in every slot, leaving \code{}$dataptr\edoc{} pointing to the first free word}\endmoddef ! 3370: b 2f ! 3371: 1: sw $10,0($dataptr) /* store the value */ ! 3372: addi $dataptr,4 /* on to the next word */ ! 3373: 2: bne $dataptr,$artemp3,1b /* if not off the end, repeat */ ! 3374: ! 3375: ! 3376: \endcode ! 3377: \begindocs{16} ! 3378: \code{}create_b(n)\edoc{} creates a byte-array of length $n$, and ! 3379: \code{}create_s(n)\edoc{} creates a string of length $n$. ! 3380: ! 3381: We use the same code to create byte arrays and strings, since the only ! 3382: difference is in the tags. ! 3383: The odd arrangement of closures (odd because each one starts a new record) ! 3384: causes no problems because this code isn't in the garbage-collectible region. ! 3385: \enddocs ! 3386: \begincode{17} ! 3387: \moddef{string and bytearray}\endmoddef ! 3388: Closure(create_b_v) ! 3389: addi $artemp3,$0,tag_bytearray /* tag into $artemp3 */ ! 3390: b 2f ! 3391: Closure(create_s_v) ! 3392: addi $artemp3,$0,tag_string /* tag into $artemp3 */ ! 3393: 2: ! 3394: \endcode ! 3395: \begindocs{18} ! 3396: The length computation may be a bit confusing. ! 3397: We are handed a tagged integer $2n+1$, and we need to compute the required ! 3398: number of words, which is $\lfloor{n+3\over 4}\rfloor$. ! 3399: This is just $\lfloor{(2n+1)+5\over 8}\rfloor$. ! 3400: However, we'll save an instruction later if we happen to have one more than ! 3401: the number of words tucked away in a register, ! 3402: because $1+\lfloor{n+3\over 4}\rfloor$ is the number of words ! 3403: we're taking from the data space (we include the descriptor). ! 3404: So we compute $(2n+1)+13$ and continue accordingly ! 3405: \enddocs ! 3406: \begincode{19} ! 3407: \moddef{string and bytearray}\endmoddef ! 3408: addi $artemp1,$stdarg,13 /* $2n+14$ */ ! 3409: sra $artemp1,3 /* number of words in string+tag */ ! 3410: sll $artemp1,2 /* # of bytes allocated for str+tag */ ! 3411: .set noreorder /* don't cross gc boundary */ ! 3412: add $artemp2,$artemp1,$dataptr /* beyond last word of string */ ! 3413: badgc2: sw $0,-4($artemp2) /* clear last; causes allocation */ ! 3414: .set reorder ! 3415: sra $artemp2,$stdarg,1 /* untagged length in bytes */ ! 3416: sll $artemp2,width_tags /* room for descriptor */ ! 3417: or $artemp2,$artemp3 /* descriptor */ ! 3418: sw $artemp2,0($dataptr) /* store descriptor */ ! 3419: addi $stdarg,$dataptr,4 /* pointer to new string */ ! 3420: add $dataptr,$artemp1 /* advance; save 1 instruction */ ! 3421: lw $10,0($stdcont) /* grab continuation */ ! 3422: j $10 /* return */ ! 3423: ! 3424: \endcode ! 3425: \begincode{20} ! 3426: \moddef{load bad pc into \code{}$artemp2\edoc{}; branch to \code{}badpc\edoc{} if == \code{}$artemp1\edoc{}}\endmoddef ! 3427: la $artemp2,badgc2 ! 3428: beq $artemp1,$artemp2,badpc ! 3429: ! 3430: \endcode ! 3431: \begindocs{21} ! 3432: \subsection{Linkage with C code} ! 3433: C always gains control first, and stuffs something appropriate into ! 3434: the register save areas before starting ML by calling \code{}restoreregs\edoc{}. ! 3435: It also puts something appropriate in the ML \code{}saved_pc\edoc{}. ! 3436: \code{}restoreregs\edoc{} squirrels away the current state of the C runtime stack, ! 3437: restores the ML registers, and finally jumps to the saved program counter. ! 3438: ! 3439: When ML wants to call C, it calls \code{}saveregs\edoc{}, which saves the ML state ! 3440: in the appropriate save areas, then restores the C runtime stack and returns. ! 3441: Before returning to C, it sets \code{}cause\edoc{} to something appropriate. ! 3442: ! 3443: All programs must ensure that \code{}restoreregs\edoc{} {\em never} calls itself ! 3444: recursively, because it is {\em not} reentrant. ! 3445: ! 3446: The C end of this connection is on display in the \code{}runML()\edoc{} function of ! 3447: \code{}~ml/src/runtime/callgc.c\edoc{}. ! 3448: \enddocs ! 3449: \begincode{22} ! 3450: \moddef{data segment items}\endmoddef ! 3451: bottom: .word 0 /* C's saved stack pointer */ ! 3452: \endcode ! 3453: \begincode{23} ! 3454: \moddef{C linkage}\endmoddef ! 3455: .globl saveregs ! 3456: .globl handle_c ! 3457: .globl return_c ! 3458: .globl restoreregs ! 3459: .ent restoreregs ! 3460: restoreregs: ! 3461: \LA{}save caller's stuff using MIPS calling conventions\RA{} ! 3462: \LA{}enable floating point overflow and zerodivide exceptions\RA{} ! 3463: sw $sp,bottom /* save C's stack pointer */ ! 3464: \LA{}if \code{}saved_pc\edoc{} points to a bad spot, adjust it (destroys arithmetic temps)\RA{} ! 3465: \LA{}restore the ML registers\RA{} ! 3466: .set noat /* This trick will cause a warning, but the code is OK */ ! 3467: lw $at,saved_pc /* grab the saved program counter */ ! 3468: j $at /* and continue executing at that spot */ ! 3469: .set at ! 3470: ! 3471: \endcode ! 3472: \begindocs{24} ! 3473: The next two functions are an exception handler and a continuation for ! 3474: ML programs called from C. ! 3475: Although neither appears to return any result (by manipulating \code{}$stdarg\edoc{}, ! 3476: they do return results. ! 3477: It's just that the C code on the other end gets the result out of ! 3478: \code{}saved_ptrs[0],\edoc{} where it expects to find \code{}$stdarg\edoc{}. ! 3479: \enddocs ! 3480: \begincode{25} ! 3481: \moddef{C linkage}\endmoddef ! 3482: Closure(handle_c) /* exception handler for ML functions called from C */ ! 3483: li $artemp1,CAUSE_EXN ! 3484: sw $artemp1,cause ! 3485: b saveregs ! 3486: Closure(return_c) /* continuation for ML functions called from C */ ! 3487: li $artemp1,CAUSE_RET ! 3488: sw $artemp1,cause ! 3489: saveregs: ! 3490: \LA{}save the ML registers\RA{} ! 3491: lw $sp,bottom /* recover C's stack pointer */ ! 3492: \LA{}restore caller's stuff using MIPS calling conventions\RA{} ! 3493: j $31 /* return to C program */ ! 3494: .end restoreregs ! 3495: ! 3496: \endcode ! 3497: \begincode{26} ! 3498: \moddef{enable floating point overflow and zerodivide exceptions}\endmoddef ! 3499: .set noat ! 3500: cfc1 $at,$31 /* grab fpa control register */ ! 3501: ori $at,$at,0x600 /* set O and Z bits */ ! 3502: ctc1 $at,$31 /* return fpa control register */ ! 3503: .set at ! 3504: ! 3505: \endcode ! 3506: \begindocs{27} ! 3507: The MIPS calling conventions are described in gory detail in Appendix~D ! 3508: of the MIPS book; pages D-18 and following. ! 3509: ! 3510: At the moment we don't save any floating point registers. ! 3511: We save (on the stack) nine general-purpose registers, the global pointer, ! 3512: and the return address. ! 3513: ! 3514: We always have to allocate at least 16 bytes for argument build, ! 3515: because any C function might be varargs, and might begin by ! 3516: spilling all of its registers into the argument build area (Hanson). ! 3517: We allocate exactly sixteen bytes, planning to fiddle the stack if ! 3518: (God forbid) we are ever asked to issue a system call with more than ! 3519: 16 bytes worth of arguments. ! 3520: ! 3521: \enddocs ! 3522: \begincode{28} ! 3523: \moddef{save caller's stuff using MIPS calling conventions}\endmoddef ! 3524: #define regspace 44 ! 3525: #define localspace 4 ! 3526: #define argbuild 16 ! 3527: #define framesize (regspace+localspace+argbuild) /* must be multiple of 8 */ ! 3528: #define frameoffset (0-localspace) ! 3529: subu $sp,framesize ! 3530: \LA{}give .mask and save the C registers\RA{} ! 3531: ! 3532: \endcode ! 3533: \begincode{29} ! 3534: \moddef{restore caller's stuff using MIPS calling conventions}\endmoddef ! 3535: \LA{}restore the C registers\RA{} ! 3536: addu $sp,framesize ! 3537: \endcode ! 3538: \begindocs{30} ! 3539: We don't save floating point regs yet. ! 3540: \enddocs ! 3541: \begincode{31} ! 3542: \moddef{give .mask and save the C registers}\endmoddef ! 3543: .mask 0xd0ff0000,0-localspace ! 3544: sw $31,argbuild+40($sp) ! 3545: sw $30,argbuild+36($sp) ! 3546: sw $gp,argbuild+32($sp) ! 3547: sw $23,argbuild+28($sp) ! 3548: sw $22,argbuild+24($sp) ! 3549: sw $21,argbuild+20($sp) ! 3550: sw $20,argbuild+16($sp) ! 3551: sw $19,argbuild+12($sp) ! 3552: sw $18,argbuild+8($sp) ! 3553: sw $17,argbuild+4($sp) ! 3554: sw $16,argbuild($sp) ! 3555: \endcode ! 3556: \begincode{32} ! 3557: \moddef{restore the C registers}\endmoddef ! 3558: lw $31,argbuild+40($sp) ! 3559: lw $30,argbuild+36($sp) ! 3560: lw $gp,argbuild+32($sp) ! 3561: lw $23,argbuild+28($sp) ! 3562: lw $22,argbuild+24($sp) ! 3563: lw $21,argbuild+20($sp) ! 3564: lw $20,argbuild+16($sp) ! 3565: lw $19,argbuild+12($sp) ! 3566: lw $18,argbuild+8($sp) ! 3567: lw $17,argbuild+4($sp) ! 3568: lw $16,argbuild($sp) ! 3569: ! 3570: ! 3571: \endcode ! 3572: \begindocs{33} ! 3573: There are two save areas; one for pointers and one for non-pointers. ! 3574: (The pointer area may, of course, include tagged integers.) ! 3575: The pointer area has special spots for standard argument, continuation, ! 3576: and closure. ! 3577: In addition there are special save areas for the special registers. ! 3578: Register 31 is to be maintained constant relative to the program counter, ! 3579: so we store the difference with \code{}saved_pc\edoc{}. ! 3580: \enddocs ! 3581: \begincode{34} ! 3582: \moddef{save the ML registers}\endmoddef ! 3583: /* needn't save $1 */ ! 3584: /* the big three: argument, continuation, closure */ ! 3585: sw $stdarg,saved_ptrs ! 3586: sw $stdcont,saved_ptrs+4 ! 3587: sw $stdclos,saved_ptrs+8 ! 3588: ! 3589: /* All the miscellaneous guys */ ! 3590: sw $5,saved_ptrs+12 ! 3591: sw $6,saved_ptrs+16 ! 3592: sw $7,saved_ptrs+20 ! 3593: sw $8,saved_ptrs+24 ! 3594: sw $9,saved_ptrs+28 ! 3595: sw $10,saved_ptrs+32 ! 3596: sw $11,saved_ptrs+36 ! 3597: sw $12,saved_ptrs+40 ! 3598: sw $13,saved_ptrs+44 ! 3599: sw $14,saved_ptrs+48 ! 3600: sw $15,saved_ptrs+52 ! 3601: sw $16,saved_ptrs+56 ! 3602: sw $17,saved_ptrs+60 ! 3603: sw $18,saved_ptrs+64 ! 3604: sw $19,saved_ptrs+68 ! 3605: ! 3606: sw $21, saved_ptrs+72 ! 3607: ! 3608: sw $artemp1,saved_nonptrs ! 3609: sw $artemp2,saved_nonptrs+4 ! 3610: sw $artemp3,saved_nonptrs+8 ! 3611: ! 3612: /* don't touch registers $26 and $27 */ ! 3613: ! 3614: sw $storeptr,saved_storeptr ! 3615: sw $dataptr,saved_dataptr ! 3616: sw $exnptr,saved_exnptr ! 3617: ! 3618: \LA{}save $\code{}$31\edoc{}-\code{}saved_pc\edoc{}$ in \code{}saved_pc_diff\edoc{} (destroys \code{}$artemp1\edoc{})\RA{} ! 3619: ! 3620: ! 3621: \endcode ! 3622: \begincode{35} ! 3623: \moddef{restore the ML registers}\endmoddef ! 3624: /* the big three: argument, continuation, closure */ ! 3625: lw $stdarg,saved_ptrs ! 3626: lw $stdcont,saved_ptrs+4 ! 3627: lw $stdclos,saved_ptrs+8 ! 3628: ! 3629: /* All the miscellaneous guys */ ! 3630: lw $5,saved_ptrs+12 ! 3631: lw $6,saved_ptrs+16 ! 3632: lw $7,saved_ptrs+20 ! 3633: lw $8,saved_ptrs+24 ! 3634: lw $9,saved_ptrs+28 ! 3635: lw $10,saved_ptrs+32 ! 3636: lw $11,saved_ptrs+36 ! 3637: lw $12,saved_ptrs+40 ! 3638: lw $13,saved_ptrs+44 ! 3639: lw $14,saved_ptrs+48 ! 3640: lw $15,saved_ptrs+52 ! 3641: lw $16,saved_ptrs+56 ! 3642: lw $17,saved_ptrs+60 ! 3643: lw $18,saved_ptrs+64 ! 3644: lw $19,saved_ptrs+68 ! 3645: ! 3646: lw $21, saved_ptrs+72 ! 3647: ! 3648: \LA{}restore \code{}$31\edoc{} from \code{}saved_pc\edoc{} \& \code{}saved_pc_diff\edoc{} (destroys \code{}$artemp1\edoc{})\RA{} ! 3649: lw $artemp1,saved_nonptrs ! 3650: lw $artemp2,saved_nonptrs+4 ! 3651: lw $artemp3,saved_nonptrs+8 ! 3652: ! 3653: /* don't touch registers $26 and $27 */ ! 3654: ! 3655: lw $storeptr,saved_storeptr ! 3656: lw $dataptr,saved_dataptr ! 3657: lw $exnptr,saved_exnptr ! 3658: ! 3659: \endcode ! 3660: \begincode{36} ! 3661: \moddef{save $\code{}$31\edoc{}-\code{}saved_pc\edoc{}$ in \code{}saved_pc_diff\edoc{} (destroys \code{}$artemp1\edoc{})}\endmoddef ! 3662: lw $artemp1,saved_pc ! 3663: subu $artemp1,$31,$artemp1 /* mustn't overflow */ ! 3664: sw $artemp1,saved_pc_diff ! 3665: \endcode ! 3666: \begincode{37} ! 3667: \moddef{restore \code{}$31\edoc{} from \code{}saved_pc\edoc{} \& \code{}saved_pc_diff\edoc{} (destroys \code{}$artemp1\edoc{})}\endmoddef ! 3668: lw $artemp1,saved_pc ! 3669: lw $31,saved_pc_diff ! 3670: addu $31,$artemp1 /* mustn't overflow */ ! 3671: \endcode ! 3672: \begincode{38} ! 3673: \moddef{data segment items}\endmoddef ! 3674: saved_pc_diff: .word 0 ! 3675: ! 3676: ! 3677: \endcode ! 3678: \begindocs{39} ! 3679: Because the Mips has no indexed addressing modes, there are special ! 3680: circumstances under which we have to adjust the program counter before ! 3681: a garbage collection. ! 3682: The problem arises when we want to create an object whose size is not ! 3683: known at compile time. ! 3684: In order to do that, we have to add the size of the object to \code{}$dataptr\edoc{}, ! 3685: putting the result in a new register. ! 3686: We then store at offset $-4$ from that register to allocate (and possibly ! 3687: cause garbage collection). ! 3688: That register can't be a pointer, because at the time of the gc it doesn't ! 3689: point to anything sensible (in fact, by definition it points out of the ! 3690: garbage-collectible region entirely). ! 3691: If it is a nonpointer, though, it isn't changed by the garbage collection, ! 3692: so when the collection is over, we attempt once again to store in exactly ! 3693: the same place, causing another fault (unless the heap has been resized). ! 3694: ! 3695: The solution is a hack. Since there are only two places this problem ! 3696: can occur, we check \code{}saved_pc\edoc{} against the offending program counters. ! 3697: If we find one, we reduce \code{}saved_pc\edoc{} by 4 (the size of one instruction), ! 3698: causing the addition to be repeated. ! 3699: ! 3700: \enddocs ! 3701: \begincode{40} ! 3702: \moddef{if \code{}saved_pc\edoc{} points to a bad spot, adjust it (destroys arithmetic temps)}\endmoddef ! 3703: lw $artemp1,saved_pc ! 3704: \LA{}load bad pc into \code{}$artemp2\edoc{}; branch to \code{}badpc\edoc{} if == \code{}$artemp1\edoc{}\RA{} ! 3705: b 1f ! 3706: badpc: ! 3707: subu $artemp1,4 /* adjust */ ! 3708: sw $artemp1,saved_pc /* save */ ! 3709: 1: ! 3710: ! 3711: ! 3712: \endcode ! 3713: \begindocs{41} ! 3714: \code{}callc(f,a)\edoc{} calls a C-language function \code{}f\edoc{} with argument \code{}a\edoc{}. ! 3715: We don't have to save a register unless we'll need its value later. ! 3716: ! 3717: The closure of this routine is irrelevant, since \code{}callc\edoc{} doesn't ! 3718: have any free variables. ! 3719: Therefore the only things that have to be restored after the call to~C ! 3720: are the continuation, the store pointer, the data pointer, and ! 3721: the exception handler. ! 3722: If we wanted \code{}callc\edoc{} to be more efficient, we would ! 3723: rearrange things so that all those registers fell into \code{}s0\edoc{}--\code{}s8\edoc{}, ! 3724: where they would automatically be preserved across procedure calls. ! 3725: As it stands, everything except the continuation is preserved, ! 3726: so we're not doing too badly. ! 3727: ! 3728: Miraculously, C routines return integer results in \code{}$2\edoc{}, which is ! 3729: exactly the register we need to pass to our continuation (in order to ! 3730: return a value). ! 3731: I decided not to rely on this, and to include a \code{}move\edoc{} instruction ! 3732: anyway. Maybe the assembler will park it in a delay slot since it ! 3733: is a nop. ! 3734: \enddocs ! 3735: \begincode{42} ! 3736: \moddef{calling C routines}\endmoddef ! 3737: Closure(callc_v) ! 3738: sw $stdcont,argbuild+regspace($sp) /* save continuation on stack */ ! 3739: lw $4,4($stdarg) /* get value a into arg register */ ! 3740: lw $10,0($stdarg) /* get address of f into misc reg */ ! 3741: jal $10 /* call f ($31 can be trashed) */ ! 3742: move $stdarg,$2 /* return val is argument to continuation */ ! 3743: lw $stdcont,argbuild+regspace($sp) /* recover continuation */ ! 3744: \LA{}put zeroes in all forwardable regs that might hold garbage\RA{} ! 3745: lw $artemp3,cause /* get cause */ ! 3746: bne $artemp3,$0,saveregs /* if cause != 0, save ML & return to C */ ! 3747: lw $10,0($stdcont) /* grab continuation */ ! 3748: j $10 /* return */ ! 3749: \endcode ! 3750: \begindocs{43} ! 3751: A forwardable register can hold garbage unless it was saved ! 3752: by C (is in \code{}s0\edoc{}--\code{}s8\edoc{}) or is \code{}$stdarg\edoc{} of \code{}$stdcont\edoc{}. ! 3753: \enddocs ! 3754: \begincode{44} ! 3755: \moddef{put zeroes in all forwardable regs that might hold garbage}\endmoddef ! 3756: move $stdclos,$0 ! 3757: move $5,$0 ! 3758: move $6,$0 ! 3759: move $7,$0 ! 3760: move $8,$0 ! 3761: move $9,$0 ! 3762: move $10,$0 ! 3763: move $11,$0 ! 3764: move $12,$0 ! 3765: move $13,$0 ! 3766: move $14,$0 ! 3767: move $15,$0 ! 3768: /* $16--$23 and $30 are saved by the callee */ ! 3769: ! 3770: \endcode ! 3771: \begindocs{45} ! 3772: This interface is going to be agony, because the rules for passing ! 3773: arguments are passing strange. ! 3774: The interface is \code{}syscall_v(callnumber,argvector,argcount)\edoc{}. ! 3775: ! 3776: The system call interface is the same as the procedure call interface, ! 3777: but instead of a \code{}jal\edoc{} we use a \code{}syscall\edoc{} instruction, and ! 3778: we put the system call number in register \code{}$2\edoc{}. ! 3779: It appears that, after the execution of the \code{}syscall\edoc{} handler, ! 3780: the result is in \code{}$2\edoc{}, and \code{}$7\edoc{} is zero unless an error occurred. ! 3781: We will put all the arguments on the stack, then load the first four ! 3782: into \code{}$4\edoc{}--\code{}$7\edoc{}. ! 3783: \enddocs ! 3784: \begincode{46} ! 3785: \moddef{system calls}\endmoddef ! 3786: Closure(syscall_v) ! 3787: sw $stdcont,argbuild+regspace($sp) /* save continuation on stack */ ! 3788: lw $artemp1,8($stdarg) /* 2*argc+1 in $artemp1 */ ! 3789: sra $artemp1,1 /* argc in $artemp1 */ ! 3790: move $16,$sp /* save our $sp */ ! 3791: \LA{}extend argbuild area to be big enough for all arguments\RA{} ! 3792: lw $ptrtemp,4($stdarg) /* argv in $ptrtemp */ ! 3793: \LA{}put all arguments onto the stack\RA{} ! 3794: \LA{}load first four arguments into \code{}$4\edoc{}--\code{}$7\edoc{}\RA{} ! 3795: 9: lw $2,0($stdarg) /* get syscall # in $2; trash $stdarg */ ! 3796: sra $2,1 /* throw out the tag bit */ ! 3797: syscall ! 3798: move $sp,$16 /* recover the good stack pointer */ ! 3799: lw $stdcont,argbuild+regspace($sp) /* recover continuation */ ! 3800: bnez $7,1f /* if error, return ~1 */ ! 3801: move $stdarg,$2 /* return val is argument to continuation */ ! 3802: add $stdarg,$stdarg /* double return value */ ! 3803: addi $stdarg,1 /* and add tag bit */ ! 3804: b 2f ! 3805: 1: li $stdarg,-1 ! 3806: 2: ! 3807: \LA{}put zeroes in all forwardable regs that might hold garbage\RA{} ! 3808: lw $10,0($stdcont) /* grab continuation */ ! 3809: j $10 /* return */ ! 3810: ! 3811: \endcode ! 3812: \begindocs{47} ! 3813: At this point we know that the number of arguments is in \code{}$artemp1\edoc{}. ! 3814: We have room for four arguments; if there are more ! 3815: we'll have to increase the stack size by the appropriate multiple of 8 ! 3816: so that it stays doubleword-aligned. ! 3817: \enddocs ! 3818: \begincode{48} ! 3819: \moddef{extend argbuild area to be big enough for all arguments}\endmoddef ! 3820: ble $artemp1,4,1f /* big enough */ ! 3821: sub $artemp2,$artemp1,3 /* (temp2 = argc - 4 + 1) > 1 */ ! 3822: sra $artemp2,1 ! 3823: sll $artemp2,3 /* temp2 = 4 * roundup (argc-4,2) */ ! 3824: subu $sp,$artemp2 /* increase stack */ ! 3825: 1: ! 3826: ! 3827: \endcode ! 3828: \begindocs{49} ! 3829: Now we have a list of arguments pointed to by \code{}$ptrtemp\edoc{}. ! 3830: We have the count of the arguments in \code{}$artemp1\edoc{}. ! 3831: We have to put them on the stack. ! 3832: We have to remove tag bits where appropriate. ! 3833: \enddocs ! 3834: \begincode{50} ! 3835: \moddef{put all arguments onto the stack}\endmoddef ! 3836: move $artemp2,$sp /* destination in $artemp2 */ ! 3837: b 1f /* branch forward to test */ ! 3838: 2: /* argc > 0 */ ! 3839: lw $artemp3,0($ptrtemp) /* get list element */ ! 3840: andi $10,$artemp3,1 /* tagged? */ ! 3841: beqz $10,3f ! 3842: sra $artemp3,1 /* drop tag bit */ ! 3843: 3: sw $artemp3,0($artemp2) /* save the argument */ ! 3844: lw $ptrtemp,4($ptrtemp) /* next element */ ! 3845: add $artemp2,4 /* next arg build area */ ! 3846: sub $artemp1,1 /* --argc */ ! 3847: 1: bgtz $artemp1,2b /* if argc>0, store another */ ! 3848: ! 3849: \endcode ! 3850: \begindocs{51} ! 3851: It doesn't matter if we load arguments that aren't there; the ! 3852: system call will just ignore them. ! 3853: \enddocs ! 3854: \begincode{52} ! 3855: \moddef{load first four arguments into \code{}$4\edoc{}--\code{}$7\edoc{}}\endmoddef ! 3856: lw $4,0($sp) ! 3857: lw $5,4($sp) ! 3858: lw $6,8($sp) ! 3859: lw $7,12($sp) ! 3860: ! 3861: \endcode ! 3862: \begindocs{53} ! 3863: \subsection{Floating point} ! 3864: We store floating point constants in two words, with the least significant ! 3865: word first. ! 3866: We use the 64 bit IEEE format. ! 3867: ! 3868: We begin with instructions to change the rounding modes. ! 3869: See the MIPS book, pages 6-5--6-7. ! 3870: \enddocs ! 3871: \begincode{54} ! 3872: \moddef{tell the floating point unit to round toward $-\infty$}\endmoddef ! 3873: .set noat ! 3874: cfc1 $at,$31 /* grab fpa control register */ ! 3875: ori $at,0x03 /* set rounding bits to 11 */ ! 3876: ctc1 $at,$31 /* return fpa control register */ ! 3877: .set at ! 3878: \endcode ! 3879: \begincode{55} ! 3880: \moddef{tell the floating point unit to round to nearest}\endmoddef ! 3881: .set noat ! 3882: cfc1 $at,$31 /* grab fpa control register */ ! 3883: ori $at,0x03 /* set rounding bits to 11 */ ! 3884: xori $at,0x03 /* set rounding bits to 00 ! 3885: ctc1 $at,$31 /* return fpa control register */ ! 3886: .set at ! 3887: \endcode ! 3888: \begindocs{56} ! 3889: These floating point functions are used int floating to integer conversion. ! 3890: \enddocs ! 3891: \begincode{57} ! 3892: \moddef{floating point}\endmoddef ! 3893: /* Floating exceptions raised (assuming ROP's are never passed to functions): ! 3894: * DIVIDE BY ZERO - (div) ! 3895: * OVERFLOW/UNDERFLOW - (add,div,sub,mul) as appropriate ! 3896: * ! 3897: * floor raises integer overflow if the float is out of 32-bit range, ! 3898: * so the float is tested before conversion, to make sure it is in (31-bit) ! 3899: * range */ ! 3900: ! 3901: \endcode ! 3902: \begindocs{58} ! 3903: \code{}floor(x)\edoc{} returns the smallest integer less than or equal to \code{}x\edoc{}. ! 3904: \enddocs ! 3905: \begincode{59} ! 3906: \moddef{floating point}\endmoddef ! 3907: Closure(floor_v) ! 3908: lwc1 $f4,0($stdarg) /* get least significant word */ ! 3909: lwc1 $f5,4($stdarg) /* get most significant word */ ! 3910: \LA{}tell the floating point unit to round toward $-\infty$\RA{} ! 3911: cvt.w.d $f6,$f4 /* convert to integer */ ! 3912: \LA{}tell the floating point unit to round to nearest\RA{} ! 3913: mfc1 $stdarg,$f6 /* get in std argument register */ ! 3914: sll $stdarg,1 /* make room for tag bit */ ! 3915: add $stdarg,1 /* add the tag bit */ ! 3916: lw $10,0($stdcont) /* grab continuation */ ! 3917: j $10 /* return */ ! 3918: ! 3919: ! 3920: \endcode ! 3921: \begindocs{60} ! 3922: \code{}logb(x)\edoc{} returns the exponent part of the floating point \code{}x\edoc{}. ! 3923: We grab the 11-bit exponent from the word, then unbias it (according ! 3924: to the IEEE standard) by subtracting 1023. ! 3925: \enddocs ! 3926: \begincode{61} ! 3927: \moddef{floating point}\endmoddef ! 3928: Closure(logb_v) ! 3929: lw $stdarg,4($stdarg) /* most significant part */ ! 3930: srl $stdarg,20 /* throw out 20 low bits */ ! 3931: andi $stdarg,0x07ff /* clear all but 11 low bits */ ! 3932: sub $stdarg,1023 /* subtract 1023 */ ! 3933: sll $stdarg,1 /* make room for tag bit */ ! 3934: add $stdarg,1 /* add the tag bit */ ! 3935: lw $10,0($stdcont) /* grab continuation */ ! 3936: j $10 /* return */ ! 3937: ! 3938: \endcode ! 3939: \begindocs{62} ! 3940: \code{}scalb(x,n)\edoc{} adds \code{}n\edoc{} to the exponent of floating ! 3941: point \code{}x\edoc{}. ! 3942: Since we don't want the resulting float to be anything ! 3943: special, we insist that the unbiased exponent of the result ! 3944: satisfy $-1022 \le E \le 1023$, i.e.\ that the biased exponent satisfy ! 3945: $1 \le e \le 2046$. ! 3946: \enddocs ! 3947: \begincode{63} ! 3948: \moddef{floating point}\endmoddef ! 3949: Closure(scalb_v) ! 3950: lw $artemp1,4($stdarg) /* get tagged n */ ! 3951: sra $artemp1,1 /* get real n */ ! 3952: beqz $artemp1,9f /* if zero, return the old float */ ! 3953: lw $ptrtemp,0($stdarg) /* get pointer to float */ ! 3954: lw $artemp2,4($ptrtemp) /* most significant part */ ! 3955: srl $artemp2,20 /* throw out 20 low bits */ ! 3956: andi $artemp2,0x07ff /* clear all but 11 low bits */ ! 3957: add $artemp3,$artemp2,$artemp1 /* new := old + n */ ! 3958: blt $artemp3,1,under /* punt if underflow */ ! 3959: bgt $artemp3,2046,over /* or overflow */ ! 3960: \LA{}allocate and store new floating point constant and set \code{}$stdarg\edoc{}\RA{} ! 3961: lw $10,0($stdcont) /* grab continuation */ ! 3962: j $10 /* return */ ! 3963: ! 3964: 9: lw $stdarg,0($stdarg) /* get old float */ ! 3965: lw $10,0($stdcont) /* grab continuation */ ! 3966: j $10 /* return */ ! 3967: ! 3968: over: la $stdarg,1f /* exception name in $stdarg */ ! 3969: b raise_real ! 3970: String(1,8,"overflow") ! 3971: under: la $stdarg,1f /* exception name in $stdarg */ ! 3972: b raise_real ! 3973: String(1,9,"underflow\\0\\0\\0") ! 3974: ! 3975: raise_real: ! 3976: /* build new record to pass to exception handler */ ! 3977: /* [descriptor] ! 3978: /* [exception (string)] ! 3979: /* [real_e (more exception info)] ! 3980: */ ! 3981: la $10,real_e /* get address of real_e */ ! 3982: .set noreorder ! 3983: sw $10,8($dataptr) /* allocate; may cause gc */ ! 3984: .set reorder ! 3985: sw $stdarg,4($dataptr) ! 3986: li $10,mak_desc(2,tag_record) ! 3987: sw $10,0($dataptr) ! 3988: add $stdarg,$dataptr,4 /* new record is argument */ ! 3989: addi $dataptr,12 /* $dataptr restored */ ! 3990: move $stdclos,$exnptr /* make sure closure is right */ ! 3991: lw $10,0($exnptr) /* grab handler */ ! 3992: j $10 /* raise the exception */ ! 3993: ! 3994: \endcode ! 3995: \begindocs{64} ! 3996: Here we indulge in a little cleverness to save a couple of instructions. ! 3997: Since the old value is in \code{}$artemp2\edoc{} and the new in \code{}$artemp3\edoc{}, ! 3998: we can \code{}xor\edoc{} them, then store the new one with a second \code{}xor\edoc{}. ! 3999: \enddocs ! 4000: \begincode{65} ! 4001: \moddef{allocate and store new floating point constant and set \code{}$stdarg\edoc{}}\endmoddef ! 4002: xor $artemp3,$artemp2 /* at3 = new xor old */ ! 4003: sll $artemp3,20 /* put exponent in right position */ ! 4004: lw $artemp2,4($ptrtemp) /* most significant word */ ! 4005: xor $artemp2,$artemp3 /* change to new exponent */ ! 4006: .set noreorder ! 4007: sw $artemp2,8($dataptr) /* allocate; may cause gc */ ! 4008: .set reorder ! 4009: lw $artemp2,0($ptrtemp) /* get least significant word */ ! 4010: li $10,mak_desc(8,tag_string) /* make descriptor */ ! 4011: sw $artemp2,4($dataptr) /* save lsw */ ! 4012: sw $10,0($dataptr) /* save descriptor */ ! 4013: add $stdarg,$dataptr,4 /* get pointer to new float */ ! 4014: add $dataptr,12 /* point to new free word */ ! 4015: \endcode ! 4016: \bye
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.