|
|
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.