--- /dev/null
+#
+.sect .text; .sect .rom; .sect .data; .sect .bss
+
+/* Does a block move of words between non-overlapping buffers.
+ * Stack: ( src dst len -- )
+ */
+
+.sect .text
+.define .bls4
+.bls4:
+ lw r4, 0(sp) ! r4=len
+ lw r5, 4(sp) ! r5=dst
+ lw r6, 8(sp) ! r6=src
+ addiu sp, sp, 12
+
+ srl r4, r4, 2 ! convert len to words
+1:
+ beq r4, zero, 2f
+ nop
+
+ lw at, 0(r6)
+ sw at, 0(r5)
+ addiu r6, r6, 4
+ addiu r5, r5, 4
+ addiu r4, r4, -1
+ b 1b
+
+2:
+ jr ra
+ nop
--- /dev/null
+#
+.sect .text; .sect .rom; .sect .data; .sect .bss
+
+.sect .text
+.define .c_ui_d
+.c_ui_d:
+ /* Input: r2
+ * Output: f0
+ * Only at and f30/f31 may be used.
+ */
+ mtc1 r2, f0
+ cvt.d.w f0, f0
+ bgez r2, nonnegative
+ nop
+
+ ori at, zero, hi16[.fd_100000000]
+ ldc1 f30, lo16[.fd_100000000] (at)
+ add.d f0, f0, f30
+nonnegative:
+ jr ra
+ nop
+
+/* 4294967296 as a double. */
+.sect .rom
+.fd_100000000:
+ .data4 0, 0x41f00000
--- /dev/null
+#
+.sect .text; .sect .rom; .sect .data; .sect .bss
+
+.sect .text
+.define .c_ui_f
+.c_ui_f:
+ /* Input: r2
+ * Output: f0
+ * Only at and f30/f31 may be used.
+ */
+ mtc1 r2, f0
+ cvt.s.w f0, f0
+ bgez r2, nonnegative
+ nop
+
+ ori at, zero, hi16[.fs_100000000]
+ ldc1 f30, lo16[.fs_100000000] (at)
+ add.d f0, f0, f30
+nonnegative:
+ jr ra
+ nop
+
+/* 4294967296 as a float. */
+.sect .rom
+.fs_100000000:
+ .data4 0x4f800000
--- /dev/null
+#
+.sect .text; .sect .rom; .sect .data; .sect .bss
+
+/* Split a double-precision float into fraction and exponent, like
+ * frexp(3) in C, http://en.cppreference.com/w/c/numeric/math/frexp
+ *
+ * Stack: ( double -- fraction exponent )
+ */
+
+#define DBL_EXPBITS 11
+#define DBL_FRACHBITS 20
+#define DBL_FRACLBITS 32
+#define DBL_FRACBITS 52
+#define DBL_EXP_INFNAN 2047
+
+#define DBL_EXP_BIAS 1023
+
+.sect .text
+.define .fef8
+.fef8:
+ lw r4, 0(sp) ! r4 = low word (bits 0..31)
+ lw r5, 4(sp) ! r5 = high word (bits 32..63)
+
+ ! IEEE double = sign * 1.fraction * 2**(exponent - 1023)
+ ! sign exponent fraction
+ ! 31 30..19 18..0, 31..0
+ !
+ ! IEEE exponent = 1022 in [0.5, 1) or (-1, -0.5].
+
+ ext r7, r5, DBL_FRACHBITS, DBL_EXPBITS ! r7 = IEEE exponent
+ beq r7, zero, zeroexp ! this number is zero or denormalised, treat specially
+ nop
+
+ li at, DBL_EXP_INFNAN
+ beq r7, at, return ! just return if infinity or NaN
+ nop
+
+ addiu r7, r7, -[DBL_EXP_BIAS-1] ! undo exponent bias
+ li at, DBL_EXP_BIAS-1
+ ins r5, at, DBL_FRACHBITS, DBL_EXPBITS ! replace exponent
+return:
+ addiu sp, sp, -4 ! returning one more quad than we got
+ sw r5, 8(sp)
+ sw r6, 4(sp)
+ sw r7, 0(sp)
+ jr ra
+ nop
+
+ /* We received a denormalised number or zero. */
+zeroexp:
+ /* TODO: we just assume that the number is zero here. */
+ mov r5, zero
+ mov r6, zero
+ mov r7, zero
+ b return
+ nop