code wiki / _hdl_build / nx_rv64_asm.nx
nx_rv64_asm.nx source
↩ module page · 179 lines · 17509 B
1// nx_rv64_asm.nx -- SOVEREIGN RV64 BARE-METAL TEXT-ASSEMBLER. Two-pass (collect labels -> encode with resolved
2// branch/jump offsets) assembler emitting a FLAT binary whose entry is at offset 0 (loads at 0x80000000 via QEMU
3// `-bios`, no syscall trampoline; a guest halts via the SiFive test finisher). Reuses the RV64 format encoders proven
4// in nx_rv64_runproof_gate + adds U-type (lui) + B-type (branches). This is the tool for writing REAL device drivers
5// that boot in qemu-system-riscv64 -- readable .s text, correct bytes. license_tier: ORIGINAL
6// API: rvasm_assemble(src: *u8, n: i64, out: *u8, cap: i64) -> nbytes (or negative on error)
7// Supported: lui li addi add sub and or xor sll srl slli srli andi ori lw lbu lhu ld sw sb sh sd
8// beq bne blt bge bltu bgeu jal j mv ret nop ecall (branch/jal targets are LABELS)
9import "nx_syscalls.nx"
10const RA_MAGIC_2047: i64 = 2047
11const RA_MAGIC_2048: i64 = 2048
12
13func ra_isws(c: i64) -> i64 { if c==32 { return 1 } if c==9 { return 1 } if c==13 { return 1 } if c==10 { return 1 } return 0 }
14func ra_isdig(c: i64) -> i64 { if c>=48 { if c<=57 { return 1 } } return 0 }
15func ra_ishex(c: i64) -> i64 { if ra_isdig(c)==1 { return 1 } if c>=97 { if c<=102 { return 1 } } if c>=65 { if c<=70 { return 1 } } return 0 }
16func ra_hexval(c: i64) -> i64 { if c>=48 { if c<=57 { return c-48 } } if c>=97 { if c<=102 { return c-87 } } if c>=65 { if c<=70 { return c-55 } } return 0 }
17
18// ---- RV64 format encoders (R/I/S from the proven runproof gate; U/B added) ----
19func ra_r(op: i64, f3: i64, f7: i64, rd: i64, rs1: i64, rs2: i64) -> i64 { return (f7<<25)|((rs2&0x1F)<<20)|((rs1&0x1F)<<15)|(f3<<12)|((rd&0x1F)<<7)|op }
20func ra_i(op: i64, f3: i64, rd: i64, rs1: i64, imm: i64) -> i64 { return ((imm&0xFFF)<<20)|((rs1&0x1F)<<15)|(f3<<12)|((rd&0x1F)<<7)|op }
21func ra_s(op: i64, f3: i64, rs1: i64, rs2: i64, imm: i64) -> i64 { return (((imm>>5)&0x7F)<<25)|((rs2&0x1F)<<20)|((rs1&0x1F)<<15)|(f3<<12)|((imm&0x1F)<<7)|op }
22func ra_u(op: i64, rd: i64, imm: i64) -> i64 { return ((imm&0xFFFFF)<<12)|((rd&0x1F)<<7)|op }
23func ra_b(f3: i64, rs1: i64, rs2: i64, imm: i64) -> i64 { return (((imm>>12)&1)<<31)|(((imm>>5)&0x3F)<<25)|((rs2&0x1F)<<20)|((rs1&0x1F)<<15)|((f3&7)<<12)|(((imm>>1)&0xF)<<8)|(((imm>>11)&1)<<7)|0x63 }
24func ra_j(rd: i64, imm: i64) -> i64 { return 0x6F|((rd&0x1F)<<7)|(((imm>>12)&0xFF)<<12)|(((imm>>11)&0x1)<<20)|(((imm>>1)&0x3FF)<<21)|(((imm>>20)&0x1)<<31) }
25func ra_put(out: *u8, o: i64, w: i64) -> i64 { out[o]=(w&0xff) as u8; out[o+1]=((w>>8)&0xff) as u8; out[o+2]=((w>>16)&0xff) as u8; out[o+3]=((w>>24)&0xff) as u8; return o+4 }
26// FAIL-LOUD guard: a 12-bit signed immediate (li/addi/andi/ori) must fit [-2048,2047] or the assembler REFUSES
27// (returns 1=ok / 0=out-of-range). This is the durable fix for the "li reg, 4096 silently truncates to 0" bug --
28// a too-big immediate now fails the assemble instead of emitting wrong code (use lui for values >= 4096).
29func ra_imm12(im: i64) -> i64 { if im > RA_MAGIC_2047 { return 0 } if im < (0 - RA_MAGIC_2048) { return 0 } return 1 }
30// shift amounts (slli/srli) must fit [0,63] on RV64.
31func ra_sh6(im: i64) -> i64 { if im < 0 { return 0 } if im > 63 { return 0 } return 1 }
32
33// ---- cursor parsing ----
34func ra_skipsep(s: *u8, cur: *i64) -> i64 { var p: i64=cur[0]; var go: i64=1; while go==1 { let c: i64=s[p] as i64; if c==44 { p=p+1 } else { if ra_isws(c)==1 { p=p+1 } else { go=0 } } } cur[0]=p; return p }
35func ra_num(s: *u8, cur: *i64) -> i64 { var p: i64=cur[0]; var v: i64=0; while ra_isdig(s[p] as i64)==1 { v=v*10+((s[p] as i64)-48); p=p+1 } cur[0]=p; return v }
36func ra_imm(s: *u8, cur: *i64) -> i64 {
37 ra_skipsep(s,cur); var p: i64=cur[0]; var neg: i64=0
38 if (s[p] as i64)==45 { neg=1; p=p+1 }
39 var v: i64=0
40 if (s[p] as i64)==48 { if (s[p+1] as i64)==120 { p=p+2; while ra_ishex(s[p] as i64)==1 { v=v*16+ra_hexval(s[p] as i64); p=p+1 } cur[0]=p; if neg==1 { return 0-v } return v } }
41 while ra_isdig(s[p] as i64)==1 { v=v*10+((s[p] as i64)-48); p=p+1 }
42 cur[0]=p; if neg==1 { return 0-v } return v
43}
44func ra_past(s: *u8, cur: *i64, ch: i64) -> i64 { var p: i64=cur[0]; var go: i64=1; while go==1 { let c: i64=s[p] as i64; if c==0 { go=0 } else { if c==ch { p=p+1; go=0 } else { p=p+1 } } } cur[0]=p; return p }
45// ABI register name -> number
46func ra_reg(s: *u8, cur: *i64) -> i64 {
47 ra_skipsep(s,cur); var p: i64=cur[0]
48 let c0: i64=s[p] as i64; let c1: i64=s[p+1] as i64
49 if c0==115 { if c1==112 { cur[0]=p+2; return 2 } } // sp
50 if c0==114 { if c1==97 { cur[0]=p+2; return 1 } } // ra
51 if c0==122 { cur[0]=p+4; return 0 } // zero
52 if c0==102 { if c1==112 { cur[0]=p+2; return 8 } } // fp
53 cur[0]=p+1
54 let n: i64=ra_num(s,cur)
55 if c0==97 { return 10+n } // aN
56 if c0==116 { if n<=2 { return 5+n } return 25+n } // tN
57 if c0==115 { if n==0 { return 8 } if n==1 { return 9 } return 16+n } // sN
58 return 0
59}
60func ra_word_is(s: *u8, p: i64, lit: *u8) -> i64 { var i: i64=0; while (lit[i] as i64)!=0 { if (s[p+i] as i64)!=(lit[i] as i64) { return 0 } i=i+1 } let nc: i64=s[p+i] as i64; if ra_isws(nc)==1 { return 1 } if nc==0 { return 1 } return 0 }
61func ra_afterword(s: *u8, p: i64) -> i64 { var q: i64=p; var go: i64=1; while go==1 { let c: i64=s[q] as i64; if c==0 { go=0 } else { if ra_isws(c)==1 { go=0 } else { q=q+1 } } } return q }
62
63// label table (module-shared via params)
64func ra_find_label(s: *u8, ts: i64, tlen: i64, lst: *i64, lln: *i64, lab: *i64, nl: i64) -> i64 {
65 var j: i64=0
66 while j<nl { if lln[j]==tlen { var k: i64=0; var eq: i64=1; while k<tlen { if (s[ts+k] as i64)!=(s[(lst[j])+k] as i64) { eq=0; k=tlen } else { k=k+1 } } if eq==1 { return lab[j] } } j=j+1 }
67 return 0-1
68}
69// parse a label operand (name) at cur -> its address (or -1)
70func ra_label_target(s: *u8, cur: *i64, lst: *i64, lln: *i64, lab: *i64, nl: i64) -> i64 {
71 ra_skipsep(s,cur); let ts: i64=cur[0]; let te: i64=ra_afterword(s,ts); cur[0]=te
72 return ra_find_label(s, ts, te-ts, lst, lln, lab, nl)
73}
74
75// encode ONE instruction at line-offset fp, whose address is `abs`. returns the 32-bit word or -1.
76func ra_encode(s: *u8, fp: i64, abs: i64, lst: *i64, lln: *i64, lab: *i64, nl: i64) -> i64 {
77 let cur: *i64=sys_mmap(8) as *i64; cur[0]=ra_afterword(s,fp)
78 if ra_word_is(s,fp,"lui" as *u8)==1 { let d: i64=ra_reg(s,cur); let im: i64=ra_imm(s,cur); return ra_u(0x37,d,im) }
79 if ra_word_is(s,fp,"li" as *u8)==1 { let d: i64=ra_reg(s,cur); let im: i64=ra_imm(s,cur); if ra_imm12(im)==0 { return 0-1 } return ra_i(0x13,0,d,0,im) }
80 if ra_word_is(s,fp,"addi" as *u8)==1 { let d: i64=ra_reg(s,cur); let a: i64=ra_reg(s,cur); let im: i64=ra_imm(s,cur); if ra_imm12(im)==0 { return 0-1 } return ra_i(0x13,0,d,a,im) }
81 if ra_word_is(s,fp,"andi" as *u8)==1 { let d: i64=ra_reg(s,cur); let a: i64=ra_reg(s,cur); let im: i64=ra_imm(s,cur); if ra_imm12(im)==0 { return 0-1 } return ra_i(0x13,7,d,a,im) }
82 if ra_word_is(s,fp,"ori" as *u8)==1 { let d: i64=ra_reg(s,cur); let a: i64=ra_reg(s,cur); let im: i64=ra_imm(s,cur); if ra_imm12(im)==0 { return 0-1 } return ra_i(0x13,6,d,a,im) }
83 if ra_word_is(s,fp,"slli" as *u8)==1 { let d: i64=ra_reg(s,cur); let a: i64=ra_reg(s,cur); let im: i64=ra_imm(s,cur); if ra_sh6(im)==0 { return 0-1 } return ra_i(0x13,1,d,a,im) }
84 if ra_word_is(s,fp,"srli" as *u8)==1 { let d: i64=ra_reg(s,cur); let a: i64=ra_reg(s,cur); let im: i64=ra_imm(s,cur); if ra_sh6(im)==0 { return 0-1 } return ra_i(0x13,5,d,a,im) }
85 if ra_word_is(s,fp,"add" as *u8)==1 { let d: i64=ra_reg(s,cur); let a: i64=ra_reg(s,cur); let b: i64=ra_reg(s,cur); return ra_r(0x33,0,0,d,a,b) }
86 if ra_word_is(s,fp,"sub" as *u8)==1 { let d: i64=ra_reg(s,cur); let a: i64=ra_reg(s,cur); let b: i64=ra_reg(s,cur); return ra_r(0x33,0,0x20,d,a,b) }
87 if ra_word_is(s,fp,"and" as *u8)==1 { let d: i64=ra_reg(s,cur); let a: i64=ra_reg(s,cur); let b: i64=ra_reg(s,cur); return ra_r(0x33,7,0,d,a,b) }
88 if ra_word_is(s,fp,"or" as *u8)==1 { let d: i64=ra_reg(s,cur); let a: i64=ra_reg(s,cur); let b: i64=ra_reg(s,cur); return ra_r(0x33,6,0,d,a,b) }
89 if ra_word_is(s,fp,"xor" as *u8)==1 { let d: i64=ra_reg(s,cur); let a: i64=ra_reg(s,cur); let b: i64=ra_reg(s,cur); return ra_r(0x33,4,0,d,a,b) }
90 if ra_word_is(s,fp,"sll" as *u8)==1 { let d: i64=ra_reg(s,cur); let a: i64=ra_reg(s,cur); let b: i64=ra_reg(s,cur); return ra_r(0x33,1,0,d,a,b) }
91 if ra_word_is(s,fp,"srl" as *u8)==1 { let d: i64=ra_reg(s,cur); let a: i64=ra_reg(s,cur); let b: i64=ra_reg(s,cur); return ra_r(0x33,5,0,d,a,b) }
92 // M extension (funct7=0x01): the assembler now emits everything the emulator executes (ISA-consistent toolchain).
93 if ra_word_is(s,fp,"mulhu" as *u8)==1 { let d: i64=ra_reg(s,cur); let a: i64=ra_reg(s,cur); let b: i64=ra_reg(s,cur); return ra_r(0x33,3,0x01,d,a,b) }
94 if ra_word_is(s,fp,"mulhsu" as *u8)==1 { let d: i64=ra_reg(s,cur); let a: i64=ra_reg(s,cur); let b: i64=ra_reg(s,cur); return ra_r(0x33,2,0x01,d,a,b) }
95 if ra_word_is(s,fp,"mulh" as *u8)==1 { let d: i64=ra_reg(s,cur); let a: i64=ra_reg(s,cur); let b: i64=ra_reg(s,cur); return ra_r(0x33,1,0x01,d,a,b) }
96 if ra_word_is(s,fp,"mul" as *u8)==1 { let d: i64=ra_reg(s,cur); let a: i64=ra_reg(s,cur); let b: i64=ra_reg(s,cur); return ra_r(0x33,0,0x01,d,a,b) }
97 if ra_word_is(s,fp,"divu" as *u8)==1 { let d: i64=ra_reg(s,cur); let a: i64=ra_reg(s,cur); let b: i64=ra_reg(s,cur); return ra_r(0x33,5,0x01,d,a,b) }
98 if ra_word_is(s,fp,"div" as *u8)==1 { let d: i64=ra_reg(s,cur); let a: i64=ra_reg(s,cur); let b: i64=ra_reg(s,cur); return ra_r(0x33,4,0x01,d,a,b) }
99 if ra_word_is(s,fp,"remu" as *u8)==1 { let d: i64=ra_reg(s,cur); let a: i64=ra_reg(s,cur); let b: i64=ra_reg(s,cur); return ra_r(0x33,7,0x01,d,a,b) }
100 if ra_word_is(s,fp,"rem" as *u8)==1 { let d: i64=ra_reg(s,cur); let a: i64=ra_reg(s,cur); let b: i64=ra_reg(s,cur); return ra_r(0x33,6,0x01,d,a,b) }
101 // *W (32-bit word) ops -- OP-32 (0x3B) register + OP-IMM-32 (0x1B) immediate. ISA-consistent: fk/JIT execute these.
102 if ra_word_is(s,fp,"addiw" as *u8)==1 { let d: i64=ra_reg(s,cur); let a: i64=ra_reg(s,cur); let im: i64=ra_imm(s,cur); if ra_imm12(im)==0 { return 0-1 } return ra_i(0x1B,0,d,a,im) }
103 if ra_word_is(s,fp,"slliw" as *u8)==1 { let d: i64=ra_reg(s,cur); let a: i64=ra_reg(s,cur); let im: i64=ra_imm(s,cur); return ra_i(0x1B,1,d,a,im) }
104 if ra_word_is(s,fp,"srliw" as *u8)==1 { let d: i64=ra_reg(s,cur); let a: i64=ra_reg(s,cur); let im: i64=ra_imm(s,cur); return ra_i(0x1B,5,d,a,im) }
105 if ra_word_is(s,fp,"sraiw" as *u8)==1 { let d: i64=ra_reg(s,cur); let a: i64=ra_reg(s,cur); let im: i64=ra_imm(s,cur); return ra_i(0x1B,5,d,a,0x400|im) }
106 if ra_word_is(s,fp,"addw" as *u8)==1 { let d: i64=ra_reg(s,cur); let a: i64=ra_reg(s,cur); let b: i64=ra_reg(s,cur); return ra_r(0x3B,0,0,d,a,b) }
107 if ra_word_is(s,fp,"subw" as *u8)==1 { let d: i64=ra_reg(s,cur); let a: i64=ra_reg(s,cur); let b: i64=ra_reg(s,cur); return ra_r(0x3B,0,0x20,d,a,b) }
108 if ra_word_is(s,fp,"sllw" as *u8)==1 { let d: i64=ra_reg(s,cur); let a: i64=ra_reg(s,cur); let b: i64=ra_reg(s,cur); return ra_r(0x3B,1,0,d,a,b) }
109 if ra_word_is(s,fp,"srlw" as *u8)==1 { let d: i64=ra_reg(s,cur); let a: i64=ra_reg(s,cur); let b: i64=ra_reg(s,cur); return ra_r(0x3B,5,0,d,a,b) }
110 if ra_word_is(s,fp,"sraw" as *u8)==1 { let d: i64=ra_reg(s,cur); let a: i64=ra_reg(s,cur); let b: i64=ra_reg(s,cur); return ra_r(0x3B,5,0x20,d,a,b) }
111 if ra_word_is(s,fp,"mulw" as *u8)==1 { let d: i64=ra_reg(s,cur); let a: i64=ra_reg(s,cur); let b: i64=ra_reg(s,cur); return ra_r(0x3B,0,0x01,d,a,b) }
112 if ra_word_is(s,fp,"divuw" as *u8)==1 { let d: i64=ra_reg(s,cur); let a: i64=ra_reg(s,cur); let b: i64=ra_reg(s,cur); return ra_r(0x3B,5,0x01,d,a,b) }
113 if ra_word_is(s,fp,"divw" as *u8)==1 { let d: i64=ra_reg(s,cur); let a: i64=ra_reg(s,cur); let b: i64=ra_reg(s,cur); return ra_r(0x3B,4,0x01,d,a,b) }
114 if ra_word_is(s,fp,"remuw" as *u8)==1 { let d: i64=ra_reg(s,cur); let a: i64=ra_reg(s,cur); let b: i64=ra_reg(s,cur); return ra_r(0x3B,7,0x01,d,a,b) }
115 if ra_word_is(s,fp,"remw" as *u8)==1 { let d: i64=ra_reg(s,cur); let a: i64=ra_reg(s,cur); let b: i64=ra_reg(s,cur); return ra_r(0x3B,6,0x01,d,a,b) }
116 if ra_word_is(s,fp,"lw" as *u8)==1 { let d: i64=ra_reg(s,cur); let im: i64=ra_imm(s,cur); ra_past(s,cur,40); let a: i64=ra_reg(s,cur); return ra_i(0x03,2,d,a,im) }
117 if ra_word_is(s,fp,"lbu" as *u8)==1 { let d: i64=ra_reg(s,cur); let im: i64=ra_imm(s,cur); ra_past(s,cur,40); let a: i64=ra_reg(s,cur); return ra_i(0x03,4,d,a,im) }
118 if ra_word_is(s,fp,"lhu" as *u8)==1 { let d: i64=ra_reg(s,cur); let im: i64=ra_imm(s,cur); ra_past(s,cur,40); let a: i64=ra_reg(s,cur); return ra_i(0x03,5,d,a,im) }
119 if ra_word_is(s,fp,"ld" as *u8)==1 { let d: i64=ra_reg(s,cur); let im: i64=ra_imm(s,cur); ra_past(s,cur,40); let a: i64=ra_reg(s,cur); return ra_i(0x03,3,d,a,im) }
120 if ra_word_is(s,fp,"sw" as *u8)==1 { let v: i64=ra_reg(s,cur); let im: i64=ra_imm(s,cur); ra_past(s,cur,40); let a: i64=ra_reg(s,cur); return ra_s(0x23,2,a,v,im) }
121 if ra_word_is(s,fp,"sb" as *u8)==1 { let v: i64=ra_reg(s,cur); let im: i64=ra_imm(s,cur); ra_past(s,cur,40); let a: i64=ra_reg(s,cur); return ra_s(0x23,0,a,v,im) }
122 if ra_word_is(s,fp,"sh" as *u8)==1 { let v: i64=ra_reg(s,cur); let im: i64=ra_imm(s,cur); ra_past(s,cur,40); let a: i64=ra_reg(s,cur); return ra_s(0x23,1,a,v,im) }
123 if ra_word_is(s,fp,"sd" as *u8)==1 { let v: i64=ra_reg(s,cur); let im: i64=ra_imm(s,cur); ra_past(s,cur,40); let a: i64=ra_reg(s,cur); return ra_s(0x23,3,a,v,im) }
124 if ra_word_is(s,fp,"beq" as *u8)==1 { let a: i64=ra_reg(s,cur); let b: i64=ra_reg(s,cur); let t: i64=ra_label_target(s,cur,lst,lln,lab,nl); return ra_b(0,a,b,t-abs) }
125 if ra_word_is(s,fp,"bne" as *u8)==1 { let a: i64=ra_reg(s,cur); let b: i64=ra_reg(s,cur); let t: i64=ra_label_target(s,cur,lst,lln,lab,nl); return ra_b(1,a,b,t-abs) }
126 if ra_word_is(s,fp,"blt" as *u8)==1 { let a: i64=ra_reg(s,cur); let b: i64=ra_reg(s,cur); let t: i64=ra_label_target(s,cur,lst,lln,lab,nl); return ra_b(4,a,b,t-abs) }
127 if ra_word_is(s,fp,"bge" as *u8)==1 { let a: i64=ra_reg(s,cur); let b: i64=ra_reg(s,cur); let t: i64=ra_label_target(s,cur,lst,lln,lab,nl); return ra_b(5,a,b,t-abs) }
128 if ra_word_is(s,fp,"bltu" as *u8)==1 { let a: i64=ra_reg(s,cur); let b: i64=ra_reg(s,cur); let t: i64=ra_label_target(s,cur,lst,lln,lab,nl); return ra_b(6,a,b,t-abs) }
129 if ra_word_is(s,fp,"bgeu" as *u8)==1 { let a: i64=ra_reg(s,cur); let b: i64=ra_reg(s,cur); let t: i64=ra_label_target(s,cur,lst,lln,lab,nl); return ra_b(7,a,b,t-abs) }
130 if ra_word_is(s,fp,"jal" as *u8)==1 { let d: i64=ra_reg(s,cur); let t: i64=ra_label_target(s,cur,lst,lln,lab,nl); return ra_j(d,t-abs) }
131 if ra_word_is(s,fp,"j" as *u8)==1 { let t: i64=ra_label_target(s,cur,lst,lln,lab,nl); return ra_j(0,t-abs) }
132 if ra_word_is(s,fp,"mv" as *u8)==1 { let d: i64=ra_reg(s,cur); let a: i64=ra_reg(s,cur); return ra_i(0x13,0,d,a,0) }
133 if ra_word_is(s,fp,"ret" as *u8)==1 { return ra_i(0x67,0,0,1,0) }
134 if ra_word_is(s,fp,"nop" as *u8)==1 { return ra_i(0x13,0,0,0,0) }
135 if ra_word_is(s,fp,"ecall" as *u8)==1 { return ra_i(0x73,0,0,0,0) }
136 return 0-1
137}
138
139const RA_MAXSYM: i64 = 256
140// assemble src -> flat binary in out. returns byte length, or negative on error.
141func rvasm_assemble(s: *u8, n: i64, out: *u8, cap: i64) -> i64 {
142 let lst: *i64=sys_mmap(8*RA_MAXSYM) as *i64; let lln: *i64=sys_mmap(8*RA_MAXSYM) as *i64; let lab: *i64=sys_mmap(8*RA_MAXSYM) as *i64
143 var nl: i64=0
144 // ---- pass 1: collect labels ----
145 var pos: i64=0; var abs: i64=0
146 while pos<n {
147 var le: i64=pos; var f1: i64=1; while f1==1 { if le>=n { f1=0 } else { if (s[le] as i64)==10 { f1=0 } else { le=le+1 } } }
148 var fp: i64=pos; var f2: i64=1; while f2==1 { if fp>=le { f2=0 } else { if ra_isws(s[fp] as i64)==1 { fp=fp+1 } else { f2=0 } } }
149 if fp<le { let c0: i64=s[fp] as i64
150 if c0==35 { } else { if c0==46 { } else {
151 var q: i64=le-1; var f3: i64=1; while f3==1 { if q<fp { f3=0 } else { if ra_isws(s[q] as i64)==1 { q=q-1 } else { f3=0 } } }
152 if (s[q] as i64)==58 { if nl<RA_MAXSYM { lst[nl]=fp; lln[nl]=q-fp; lab[nl]=abs; nl=nl+1 } }
153 else { abs=abs+4 }
154 } }
155 }
156 pos=le+1
157 }
158 // ---- pass 2: encode ----
159 pos=0; abs=0
160 while pos<n {
161 var le: i64=pos; var g1: i64=1; while g1==1 { if le>=n { g1=0 } else { if (s[le] as i64)==10 { g1=0 } else { le=le+1 } } }
162 var fp: i64=pos; var g2: i64=1; while g2==1 { if fp>=le { g2=0 } else { if ra_isws(s[fp] as i64)==1 { fp=fp+1 } else { g2=0 } } }
163 if fp<le { let c0: i64=s[fp] as i64
164 if c0==35 { } else { if c0==46 { } else {
165 var q: i64=le-1; var g3: i64=1; while g3==1 { if q<fp { g3=0 } else { if ra_isws(s[q] as i64)==1 { q=q-1 } else { g3=0 } } }
166 if (s[q] as i64)==58 { } else {
167 let w: i64=ra_encode(s, fp, abs, lst, lln, lab, nl)
168 if w==(0-1) { return 0-2 }
169 if abs+4>cap { return 0-3 }
170 ra_put(out, abs, w); abs=abs+4
171 }
172 } }
173 }
174 pos=le+1
175 }
176 return abs
177}
178// convenience: assemble a null-terminated source string (computes length internally).
179func rvasm_assemble_str(s: *u8, out: *u8, cap: i64) -> i64 { var n: i64=0; while (s[n] as i64)!=0 { n=n+1 } return rvasm_assemble(s, n, out, cap) }