Add MIPS and MIPS64 seed decoding

ober

8f00c55519dc111b93243a5740a5590b90a0739e

diff --git a/README.md b/README.md
index 44f8913..2476966 100644
--- a/README.md
+++ b/README.md
@@ -22,6 +22,7 @@ make test
 make binary
 ./jasm raw --arch x86-64 --syntax intel --hex '55 48 89 e5 c3'
 ./jasm raw --arch aarch64 --hex '20 00 80 d2 c0 03 5f d6'
+./jasm raw --arch mips --hex '27 bd ff e0 03 e0 00 08'
 ```
 
 ## Library API
diff --git a/docs/plan.md b/docs/plan.md
index 1d2486b..ca80442 100644
--- a/docs/plan.md
+++ b/docs/plan.md
@@ -36,8 +36,8 @@ reference material and parity targets.
 - Seed raw-byte support exists for:
   - `x86-64`: common prologue/control-flow instructions.
   - `aarch64`: common move, add/sub, load/store, return instructions.
-- MIPS and MIPS64 are planned as first-class architecture targets, including
-  both raw-byte decoding and object-file architecture mapping.
+  - `mips`, `mipsel`, `mips64`, `mips64el`: seed fixed-width raw-byte decoding
+    for common integer/load/store/branch/jump instructions.
 - Tests cover the initial decoder slice.
 
 ## Core Architecture
@@ -688,6 +688,8 @@ Status: started.
 - ABI register-name output.
 - ELF `EM_MIPS` integration.
 
+Status: raw seed decoder started; ELF integration remains.
+
 ### Milestone 9: CLI Parity Pass
 
 - `llvm-objdump`-like option names.
diff --git a/jasm b/jasm
index b1a7f14..1e1f922 100755
Binary files a/jasm and b/jasm differ
diff --git a/lib/jasm/disasm.ss b/lib/jasm/disasm.ss
index 9f6bc78..d5e2386 100644
--- a/lib/jasm/disasm.ss
+++ b/lib/jasm/disasm.ss
@@ -162,6 +162,15 @@
        (* (bv-u8 bv (+ offset 2)) #x10000)
        (* (bv-u8 bv (+ offset 3)) #x1000000)))
 
+  (define (bv-u32-be bv offset)
+    (+ (* (bv-u8 bv offset) #x1000000)
+       (* (bv-u8 bv (+ offset 1)) #x10000)
+       (* (bv-u8 bv (+ offset 2)) #x100)
+       (bv-u8 bv (+ offset 3))))
+
+  (define (signed16 x)
+    (if (>= x #x8000) (- x #x10000) x))
+
   (define (bits n hi lo)
     (modulo (quotient n (expt 2 lo)) (expt 2 (+ 1 (- hi lo)))))
 
@@ -370,10 +379,211 @@
                    (bv-slice bv offset 4)))]
               [else (a64-unknown-word bv offset address remaining)])))))
 
+  (define mips-abi-regs
+    '#("$zero" "$at" "$v0" "$v1" "$a0" "$a1" "$a2" "$a3"
+       "$t0" "$t1" "$t2" "$t3" "$t4" "$t5" "$t6" "$t7"
+       "$s0" "$s1" "$s2" "$s3" "$s4" "$s5" "$s6" "$s7"
+       "$t8" "$t9" "$k0" "$k1" "$gp" "$sp" "$fp" "$ra"))
+
+  (define (mips-reg n options)
+    (if (eq? (option-ref options 'registers 'abi) 'numeric)
+        (string-append "$" (number->string n))
+        (vector-ref mips-abi-regs n)))
+
+  (define (mips-word arch bv offset)
+    ((if (eq? (architecture-endianness arch) 'little) bv-u32-le bv-u32-be) bv offset))
+
+  (define (mips-unknown arch bv offset address remaining)
+    (if (< remaining 4)
+        (make-instruction arch address 1
+          (string-append ".byte\t0x" (byte->hex2 (bv-u8 bv offset)))
+          (bv-slice bv offset 1))
+        (let ([word (mips-word arch bv offset)])
+          (make-instruction arch address 4
+            (string-append ".word\t0x" (number->hex word))
+            (bv-slice bv offset 4)))))
+
+  (define (mips-r3 mnemonic rd rs rt options)
+    (string-append mnemonic "\t"
+                   (mips-reg rd options) ", "
+                   (mips-reg rs options) ", "
+                   (mips-reg rt options)))
+
+  (define (mips-r-shift mnemonic rd rt shamt options)
+    (string-append mnemonic "\t"
+                   (mips-reg rd options) ", "
+                   (mips-reg rt options) ", "
+                   (number->string shamt)))
+
+  (define (mips-i3 mnemonic rt rs imm options)
+    (string-append mnemonic "\t"
+                   (mips-reg rt options) ", "
+                   (mips-reg rs options) ", "
+                   (number->string imm)))
+
+  (define (mips-i3-hex mnemonic rt rs imm options)
+    (string-append mnemonic "\t"
+                   (mips-reg rt options) ", "
+                   (mips-reg rs options) ", "
+                   (hex-number imm)))
+
+  (define (mips-load-store mnemonic rt rs imm options)
+    (string-append mnemonic "\t"
+                   (mips-reg rt options) ", "
+                   (number->string imm)
+                   "(" (mips-reg rs options) ")"))
+
+  (define (mips-branch-target address imm)
+    (+ address 4 (* (signed16 imm) 4)))
+
+  (define (mips-jump-target address index)
+    (+ (bitwise-and (+ address 4) #xf0000000)
+       (* index 4)))
+
+  (define (mips64? arch)
+    (or (eq? arch 'mips64) (eq? arch 'mips64el)))
+
+  (define (decode-mips-special arch word bv offset address options)
+    (let* ([rs (bits word 25 21)]
+           [rt (bits word 20 16)]
+           [rd (bits word 15 11)]
+           [shamt (bits word 10 6)]
+           [funct (bits word 5 0)]
+           [text
+            (cond
+              [(= word 0) "nop"]
+              [(= funct #x00) (mips-r-shift "sll" rd rt shamt options)]
+              [(= funct #x02) (mips-r-shift "srl" rd rt shamt options)]
+              [(= funct #x03) (mips-r-shift "sra" rd rt shamt options)]
+              [(= funct #x08) (string-append "jr\t" (mips-reg rs options))]
+              [(= funct #x09) (string-append "jalr\t" (mips-reg rd options) ", " (mips-reg rs options))]
+              [(= funct #x0c) "syscall"]
+              [(= funct #x0d) "break"]
+              [(= funct #x21) (mips-r3 "addu" rd rs rt options)]
+              [(= funct #x23) (mips-r3 "subu" rd rs rt options)]
+              [(= funct #x24) (mips-r3 "and" rd rs rt options)]
+              [(= funct #x25) (mips-r3 "or" rd rs rt options)]
+              [(= funct #x26) (mips-r3 "xor" rd rs rt options)]
+              [(= funct #x27) (mips-r3 "nor" rd rs rt options)]
+              [(= funct #x2a) (mips-r3 "slt" rd rs rt options)]
+              [(= funct #x2b) (mips-r3 "sltu" rd rs rt options)]
+              [(and (mips64? arch) (= funct #x2d)) (mips-r3 "daddu" rd rs rt options)]
+              [(and (mips64? arch) (= funct #x2f)) (mips-r3 "dsubu" rd rs rt options)]
+              [(and (mips64? arch) (= funct #x38)) (mips-r-shift "dsll" rd rt shamt options)]
+              [(and (mips64? arch) (= funct #x3a)) (mips-r-shift "dsrl" rd rt shamt options)]
+              [(and (mips64? arch) (= funct #x3b)) (mips-r-shift "dsra" rd rt shamt options)]
+              [(and (mips64? arch) (= funct #x3c)) (mips-r-shift "dsll32" rd rt shamt options)]
+              [(and (mips64? arch) (= funct #x3e)) (mips-r-shift "dsrl32" rd rt shamt options)]
+              [(and (mips64? arch) (= funct #x3f)) (mips-r-shift "dsra32" rd rt shamt options)]
+              [else #f])])
+      (if text
+          (make-instruction arch address 4 text (bv-slice bv offset 4))
+          (mips-unknown arch bv offset address 4))))
+
+  (define (decode-mips-regimm arch word bv offset address options)
+    (let* ([rs (bits word 25 21)]
+           [rt (bits word 20 16)]
+           [imm (bits word 15 0)]
+           [target (hex-number (mips-branch-target address imm))]
+           [mnemonic (case rt
+                       [(#x00) "bltz"]
+                       [(#x01) "bgez"]
+                       [(#x10) "bltzal"]
+                       [(#x11) "bgezal"]
+                       [else #f])])
+      (if mnemonic
+          (make-instruction arch address 4
+            (string-append mnemonic "\t" (mips-reg rs options) ", " target)
+            (bv-slice bv offset 4))
+          (mips-unknown arch bv offset address 4))))
+
+  (define (decode-mips arch bv offset address options)
+    (let* ([arch (normalize-architecture arch)]
+           [remaining (- (bytevector-length bv) offset)])
+      (if (< remaining 4)
+          (mips-unknown arch bv offset address remaining)
+          (let* ([word (mips-word arch bv offset)]
+                 [op (bits word 31 26)]
+                 [rs (bits word 25 21)]
+                 [rt (bits word 20 16)]
+                 [imm16 (bits word 15 0)]
+                 [simm (signed16 imm16)]
+                 [index (bits word 25 0)])
+            (case op
+              [(#x00) (decode-mips-special arch word bv offset address options)]
+              [(#x01) (decode-mips-regimm arch word bv offset address options)]
+              [(#x02 #x03)
+               (let ([mnemonic (if (= op #x02) "j" "jal")])
+                 (make-instruction arch address 4
+                   (string-append mnemonic "\t" (hex-number (mips-jump-target address index)))
+                   (bv-slice bv offset 4)))]
+              [(#x04 #x05)
+               (let ([mnemonic (if (= op #x04) "beq" "bne")])
+                 (make-instruction arch address 4
+                   (string-append mnemonic "\t"
+                                  (mips-reg rs options) ", "
+                                  (mips-reg rt options) ", "
+                                  (hex-number (mips-branch-target address imm16)))
+                   (bv-slice bv offset 4)))]
+              [(#x06 #x07)
+               (let ([mnemonic (if (= op #x06) "blez" "bgtz")])
+                 (make-instruction arch address 4
+                   (string-append mnemonic "\t"
+                                  (mips-reg rs options) ", "
+                                  (hex-number (mips-branch-target address imm16)))
+                   (bv-slice bv offset 4)))]
+              [(#x09)
+               (make-instruction arch address 4
+                 (mips-i3 "addiu" rt rs simm options)
+                 (bv-slice bv offset 4))]
+              [(#x0c)
+               (make-instruction arch address 4
+                 (mips-i3-hex "andi" rt rs imm16 options)
+                 (bv-slice bv offset 4))]
+              [(#x0d)
+               (make-instruction arch address 4
+                 (mips-i3-hex "ori" rt rs imm16 options)
+                 (bv-slice bv offset 4))]
+              [(#x0e)
+               (make-instruction arch address 4
+                 (mips-i3-hex "xori" rt rs imm16 options)
+                 (bv-slice bv offset 4))]
+              [(#x0f)
+               (make-instruction arch address 4
+                 (string-append "lui\t" (mips-reg rt options) ", " (hex-number imm16))
+                 (bv-slice bv offset 4))]
+              [(#x19)
+               (if (mips64? arch)
+                   (make-instruction arch address 4
+                     (mips-i3 "daddiu" rt rs simm options)
+                     (bv-slice bv offset 4))
+                   (mips-unknown arch bv offset address remaining))]
+              [(#x20 #x21 #x23 #x24 #x25 #x28 #x29 #x2b #x37 #x3f)
+               (let ([mnemonic
+                      (case op
+                        [(#x20) "lb"]
+                        [(#x21) "lh"]
+                        [(#x23) "lw"]
+                        [(#x24) "lbu"]
+                        [(#x25) "lhu"]
+                        [(#x28) "sb"]
+                        [(#x29) "sh"]
+                        [(#x2b) "sw"]
+                        [(#x37) (and (mips64? arch) "ld")]
+                        [(#x3f) (and (mips64? arch) "sd")]
+                        [else #f])])
+                 (if mnemonic
+                     (make-instruction arch address 4
+                       (mips-load-store mnemonic rt rs simm options)
+                       (bv-slice bv offset 4))
+                     (mips-unknown arch bv offset address remaining)))]
+              [else (mips-unknown arch bv offset address remaining)])))))
+
   (define (decode-instruction arch bv offset address options)
     (case (normalize-architecture arch)
       [(x86-64) (decode-x86-64 bv offset address options)]
       [(aarch64) (decode-aarch64 bv offset address options)]
+      [(mips mipsel mips64 mips64el) (decode-mips arch bv offset address options)]
       [else (error 'decode-instruction "decoder not implemented for architecture" arch)]))
 
   (define (disassemble-bytevector arch bv . maybe-options)
diff --git a/main.ss b/main.ss
index 3591252..eec0d6c 100644
--- a/main.ss
+++ b/main.ss
@@ -7,7 +7,8 @@
   (display "  jasm raw --arch <x86-64|aarch64|mips|mipsel|mips64|mips64el> [--syntax att|intel] [--address n] --hex <bytes>\n")
   (display "\nExamples:\n")
   (display "  jasm raw --arch x86-64 --syntax intel --hex '55 48 89 e5 c3'\n")
-  (display "  jasm raw --arch aarch64 --hex '20 00 80 d2 c0 03 5f d6'\n"))
+  (display "  jasm raw --arch aarch64 --hex '20 00 80 d2 c0 03 5f d6'\n")
+  (display "  jasm raw --arch mips --hex '27 bd ff e0 03 e0 00 08'\n"))
 
 (define (string->arch s)
   (normalize-architecture s))
diff --git a/tests/test-jasm.ss b/tests/test-jasm.ss
index 82da8cd..e13121d 100644
--- a/tests/test-jasm.ss
+++ b/tests/test-jasm.ss
@@ -77,6 +77,42 @@
   (one-text 'aarch64 "e0 0f 00 b9")
   "str\tw0, [sp, #0xc]")
 
+(test "mips nop"
+  (one-text 'mips "00 00 00 00")
+  "nop")
+
+(test "mips addiu big endian"
+  (one-text 'mips "27 bd ff e0")
+  "addiu\t$sp, $sp, -32")
+
+(test "mips addiu little endian"
+  (one-text 'mipsel "e0 ff bd 27")
+  "addiu\t$sp, $sp, -32")
+
+(test "mips jr"
+  (one-text 'mips "03 e0 00 08")
+  "jr\t$ra")
+
+(test "mips beq target"
+  (one-text 'mips "11 09 ff fe" '((address . #x1000)))
+  "beq\t$t0, $t1, 0xffc")
+
+(test "mips64 daddiu big endian"
+  (one-text 'mips64 "67 bd ff e0")
+  "daddiu\t$sp, $sp, -32")
+
+(test "mips64 daddiu little endian"
+  (one-text 'mips64el "e0 ff bd 67")
+  "daddiu\t$sp, $sp, -32")
+
+(test "mips64 ld"
+  (one-text 'mips64 "dc 82 00 00")
+  "ld\t$v0, 0($a0)")
+
+(test "mips numeric registers"
+  (one-text 'mips "27 bd ff e0" '((registers . numeric)))
+  "addiu\t$29, $29, -32")
+
 (test "format string"
   (disassemble->string 'x86-64
     (hex-string->bytevector "55 c3")