From 1f6ed601a14ef9bb6651a9ff0000155929473d0c Mon Sep 17 00:00:00 2001
From: ubq323 <ubq323@ubq323.website>
Date: Thu, 2 May 2024 16:15:17 +0100
Subject: e

---
 asm.py  | 154 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 r1b.txt |  70 +++++++++++++++++++++++++++++
 test.r1 |  67 ++++++++++++++++++++++++++++
 3 files changed, 291 insertions(+)
 create mode 100644 asm.py
 create mode 100644 r1b.txt
 create mode 100644 test.r1

diff --git a/asm.py b/asm.py
new file mode 100644
index 0000000..7a20f8b
--- /dev/null
+++ b/asm.py
@@ -0,0 +1,154 @@
+mnems = """
+nop
+rot
+nrt
+dup
+swp
+ovr
+drp
+tck
+nip
+equ
+neq
+add
+sub
+mul
+div
+neg
+slt
+ult
+sle
+ule
+lod
+sto
+psh
+pop
+""".split()
+mnems.extend(['???']*(64-len(mnems)))
+def opws(kw):
+	for k in range(16):
+		mnems.append(kw + str(k))
+opws("mark") # who is mark
+opws("loc")
+opws("ret")
+opws("lit")
+
+# print(mnems)
+import sys
+
+import collections
+
+pc = 0
+labels = {}
+local_labels = {}
+# map of labelname -> (dest, ifn)
+label_wants = collections.defaultdict(set)
+local_label_wants = collections.defaultdict(set)
+output = bytearray()
+
+class Wrong(Exception):
+	def __init__(self, lineno, msg):
+		self.lineno = lineno
+		self.msg = msg
+	def __str__(self):
+		return f"{self.lineno}: {self.msg}"
+
+def assemble_line(args, lineno):
+
+	match args:
+		case ["c", label] if label in labels:
+			emit_call(labels[label])
+		case ["c", label]:
+			label_wants[label].add((pc,call_instr))
+			emit(0)
+		case ['b', label] if label in local_labels:
+			emit_obranch(local_labels[label])
+		case ['b', label]:
+			local_label_wants[label].add((pc, obranch_instr))
+		case ['j', label] if label in local_labels:
+			emit_jump(local_labels[label])
+		case ['j', label]:
+			local_label_wants[label].add((pc, jump_instr))
+
+		case ["i", i1]:
+			assemble_line(["i", i1, "nop"], lineno)
+		case ["i", i1, i2]:
+			opc1 = mnems.index(i1)
+			opc2 = mnems.index(i2)
+			emit_instrs(opc1, opc2)
+		case ["l", val]:
+			emit_lit(int(val))
+		case [':', label]:
+			if label in labels:
+				raise Wrong(lineno, "label defined twice "+label)
+			labels[label] = pc
+			for (dest, ifn) in label_wants[label]:
+				put_at(dest, ifn(pc, dest))
+			del label_wants[label]
+
+			local_labels.clear()
+			for u,v in local_label_wants.items():
+				raise Wrong(lineno, "unfulfilled local label "+u)
+			local_label_wants.clear()
+
+		case ['%', label]:
+			if label in local_labels:
+				raise Wrong(lineno, "local label defined twice "+label)
+			local_labels[label] = pc
+			for (dest, ifn) in local_label_wants[label]:
+				put_at(dest, ifn(pc, dest))
+			del local_label_wants[label]
+
+		case []: pass
+
+
+		case _:
+			raise Wrong(lineno, "unknown wordtype")
+
+def emit_call(addr):
+	emit(call_instr(addr))
+def emit_instrs(opc1, opc2):
+	emit(instrs_instr(opc1, opc2))
+def emit_lit(val):
+	emit(lit_instr(val))
+def emit_obranch(addr):
+	emit(obranch_instr(addr, origin=pc))
+def emit_jump(addr):
+	emit(jump_instr(addr, origin=pc))
+
+def emit(word):
+	output.extend(word.to_bytes(2))
+	global pc
+	pc += 2
+
+def put_at(addr, word):
+	output[addr:addr+1] = word.to_bytes(2)
+
+def lit_instr(val):
+	return (val&0b1111111111111) | 0b0110000000000000
+def instrs_instr(opc1, opc2):
+	return (opc1 << 7) | opc2
+def call_instr(addr,*_):
+	return (addr>>1)|0b1000000000000000
+def obranch_instr(target, origin):
+	rel = target - origin + 2048
+	return (rel&0b111111111111)|0b0101000000000000
+def jump_instr(target, origin):
+	rel = target - origin + 2048
+	return (rel&0b111111111111)|0b0100000000000000
+
+
+
+
+import sys
+def main():
+	for ix, line in enumerate(sys.stdin):
+		line = line.strip()
+		args = line.split()
+		assemble_line(args, ix+1)
+
+	for u,v in label_wants.items():
+		print("unfulfilled global label",u, file=sys.stderr)
+	sys.stdout.buffer.write(output)
+
+if __name__ == "__main__": main()
diff --git a/r1b.txt b/r1b.txt
new file mode 100644
index 0000000..7baa9c8
--- /dev/null
+++ b/r1b.txt
@@ -0,0 +1,70 @@
+nop
+rot (abc-bca)
+-rot (abc-cab)
+dup (x-xx)
+swap (xy-yx)
+over (xy-xyx)
+drop (xy-x)
+tuck (xy-yxy)
+nip (xy-y)
+lit (-l)
+equal (xy-f)
+nequal (xy-f)
+add (xy-z)
+sub (xy-z)
+mul
+div
+neg
+slt
+ult
+sle
+ule
+lod (a-d)
+sto (da-)
+push
+pop
+
+
+
+what abotu either
+
+1[addr:15]  : call
+0 
+01 literal
+
+
+want:
+calls (15 bits)
+j, cj, relative addr, 8 bits
+lit, 4 or 8 or 16 bits
+mark,loc,ret, + 4bit arg
+regular op, no arg (between 16 and 32 of these)
+
+CALL (addr:15)
+or
+JMP (cond?:1) (rdst:rest)
+or 
+(mark/loc/ret/lit4) (arg:4)
+or
+
+regular op (7 bits)
+
+
+
+OPW:7: 1 T:2 arg:4
+OPR:7: 0 opcode:6
+	00 - 3f regular opcodes	(64 of them)
+	4x	mark x
+	5x	loc x
+	6x	ret x
+	7x	lit4 x
+
+I: 0 0 (OPW|OPR) (OPW|OPR)
+J: 0 1 0 cond? raddr:12
+L: 0 1 1 value:13
+C: 1 addr:15
+
+
+
+
+
diff --git a/test.r1 b/test.r1
new file mode 100644
index 0000000..8a51d81
--- /dev/null
+++ b/test.r1
@@ -0,0 +1,67 @@
+: sqrt
+i mark2 dup
+i loc0 sto
+c /2
+i loc1 sto
+% loop
+i loc0 lod
+i loc1 lod
+c newton
+i dup loc1
+c replace!
+c thresh
+c close?
+b loop
+i loc1 lod
+i ret2
+
+: newton
+c tuck
+c square
+i add div
+c /2
+i ret0
+
+: square
+i dup mul
+i ret0
+: tuck
+i dup nrt
+i ret0 
+
+: replace!
+i dup lod
+i nrt sto
+i ret0
+
+: close?
+i nrt
+c absdiff
+i swp sle
+i ret0
+
+: /2
+i lit2 div
+i ret0
+
+: thresh
+i lit4 ret0
+
+: absdiff
+i sub 
+
+: abs
+i lit0 slt
+b f1
+i neg
+% f1
+i ret0
+
+
+: hypot
+c square
+i swp
+c square
+i add 
+c sqrt
+i ret0
-- 
cgit v1.2.3