~jakob/chip

b43bb071d63e427834291ef1242555b82091ce9d — Jakob L. Kreuze 4 years ago fda114b
Indent with tabs.
2 files changed, 429 insertions(+), 353 deletions(-)

M asm.myr
M main.myr
M asm.myr => asm.myr +332 -342
@@ 2,384 2,374 @@ use bio
use std

const strdup = {s
    var buf = std.slalloc(s.len)
    std.slcp(buf, s)
    -> buf
	var buf = std.slalloc(s.len)
	std.slcp(buf, s)
	-> buf
}

const upcase = {s
    var i
    var buf = std.mksb()
    for i = 0; i < s.len; i++
        std.sbputc(buf, std.toupper((s[i] : char)))
    ;;
    -> std.sbfin(buf)
	var i
	var buf = std.mksb()
	for i = 0; i < s.len; i++
		std.sbputc(buf, std.toupper((s[i] : char)))
	;;
	-> std.sbfin(buf)
}

const readline = {line
    var cmt = std.strfind(line, ";")
	var cmt = std.strfind(line, ";")

    match cmt
    | `std.Some (pos): line = line[:pos]
    | `std.None:
    ;;
	match cmt
	| `std.Some (pos): line = line[:pos]
	| `std.None:
	;;

    if line.len == 0
        -> (`std.None, [][:])
    ;;
	if line.len == 0
		-> (`std.None, [][:])
	;;

    var parts = std.strtok(line)
    if std.isspace((line[0] : char))
        -> (`std.None, parts)
    else
        -> (`std.Some(parts[0]), parts[1:])
    ;;
	var parts = std.strtok(line)
	if std.isspace((line[0] : char))
		-> (`std.None, parts)
	else
		-> (`std.Some(parts[0]), parts[1:])
	;;
}

type literal = union
    `Number int
    `Register int
    `Label byte[:]
    `DerefAddr
    `Keypress
    `AddressRegister
    `DelayTimer
    `SoundTimer
    `Invalid
	`Number int
	`Register int
	`Label byte[:]
	`DerefAddr
	`Keypress
	`AddressRegister
	`DelayTimer
	`SoundTimer
	`Invalid
;;

const getnum = {s
    -> std.intparsebase((s[1:] : byte[:]), 16)
	-> std.intparsebase((s[1:] : byte[:]), 16)
}

const parselit = {s
    if s.len < 1
        -> `Invalid
    elif s[0] == ('#' : byte)
        match getnum(s)
        |`std.Some(n): -> `Number(n)
        |`std.None: -> `Invalid
        ;;
    elif s[0] == ('v' : byte) || s[0] == ('V' : byte)
        match getnum(s)
        |`std.Some(n): -> `Register(n)
        |`std.None: -> `Invalid
        ;;
    elif std.isdigit((s[0] : char))
        match std.intparsebase((s : byte[:]), 10)
        |`std.Some(n): -> `Number(n)
        |`std.None: -> `Label(s)
        ;;
    elif s[0] == ('[' : byte)
        -> `DerefAddr
    elif s[0] == ('K' : byte)
        -> `Keypress
    elif s[0] == ('I' : byte)
        -> `AddressRegister
    elif s[0] == ('D' : byte)
        -> `DelayTimer
    elif s[0] == ('S' : byte)
        -> `SoundTimer
    else
        -> `Label(s)
    ;;
	if s.len < 1
		-> `Invalid
	elif s[0] == ('#' : byte)
		match getnum(s)
		|`std.Some(n): -> `Number(n)
		|`std.None: -> `Invalid
		;;
	elif s[0] == ('v' : byte) || s[0] == ('V' : byte)
		match getnum(s)
		|`std.Some(n): -> `Register(n)
		|`std.None: -> `Invalid
		;;
	elif std.isdigit((s[0] : char))
		match std.intparsebase((s : byte[:]), 10)
		|`std.Some(n): -> `Number(n)
		|`std.None: -> `Label(s)
		;;
	elif s[0] == ('[' : byte)
		-> `DerefAddr
	elif s[0] == ('K' : byte)
		-> `Keypress
	elif s[0] == ('I' : byte)
		-> `AddressRegister
	elif s[0] == ('D' : byte)
		-> `DelayTimer
	elif s[0] == ('S' : byte)
		-> `SoundTimer
	else
		-> `Label(s)
	;;
}

const emitinstr = {p
    var b = `std.None
    var mark = `std.None
	var b = `std.None
	var mark = `std.None

    if p.len < 1
        -> `std.Ok(b, mark)
    ;;
	if p.len < 1
		-> `std.Ok(b, mark)
	;;

    match upcase(p[0])
    | "CLS":
        b = `std.Some([0x00, 0xe0])
    | "RET":
        b = `std.Some([0x00, 0xee])
    | "SYS":
        if p.len < 2
            -> `std.Err("SYS missing subroutine address")
        ;;
        match parselit(p[1])
        | `Number(n): b = `std.Some([0x00 | (n & 0x0f00), (n & 0xff)])
        | `Label(l): b = `std.Some([0x00, 0x00])
            mark = `std.Some(strdup(l))
        | _:
            -> `std.Err(std.fmt("invalid arguments to SYS: {}", p[1:]))
        ;;
    | "CALL":
        if p.len < 2
            -> `std.Err("CALL missing subroutine address")
        ;;
        match parselit(p[1])
        | `Number(n): b = `std.Some([0x20 | (n & 0x0f00), (n & 0xff)])
        | `Label(l): b = `std.Some([0x20, 0x00])
            mark = `std.Some(strdup(l))
        | _:
            -> `std.Err(std.fmt("invalid arguments to CALL: {}", p[1:]))
        ;;
    | "JP":
        if p.len < 2
            -> `std.Err("JP missing address")
        elif p.len == 2
            match parselit(p[1])
            | `Number(n): b = `std.Some([0x10 | (n & 0x0f00), (n & 0xff)])
            | `Label(l): b = `std.Some([0x10, 0x00])
                mark = `std.Some(strdup(l))
            | _:
                -> `std.Err(std.fmt("invalid arguments to JP: {}", p[1:]))
            ;;
        else
            match (parselit(p[1]), parselit(p[2]))
            | (`Register(0), `Number(n)):
                b = `std.Some([0xb0 | (n & 0x0f00), (n & 0xff)])
            | (`Register(0), `Label(l)): b = `std.Some([0xb0, 0x00])
                mark = `std.Some(strdup(l))
            | _:
                -> `std.Err(std.fmt("invalid arguments to JP: {}", p[1:]))
            ;;
        ;;
    | "SE":
        if p.len < 3
            -> `std.Err("SE missing arguments")
        ;;
        match (parselit(p[1]), parselit(p[2]))
        | (`Register(m), `Number(n)):
            b = `std.Some([0x30 | (m & 0x0f), (n & 0xff)])
        | (`Register(m), `Register(n)):
            b = `std.Some([0x50 | (m & 0x0f), (n & 0x0f) << 4])
        | _:
            -> `std.Err(std.fmt("invalid arguments to SE: {}", p[1:]))
        ;;
    | "SNE":
        if p.len < 3
            -> `std.Err("SNE missing arguments")
        ;;
        match (parselit(p[1]), parselit(p[2]))
        | (`Register(m), `Number(n)):
            b = `std.Some([0x40 | (m & 0x0f), (n & 0xff)])
        | (`Register(m), `Register(n)):
            b = `std.Some([0x90 | (m & 0x0f), (n & 0x0f) << 4])
        | _:
            -> `std.Err(std.fmt("invalid arguments to SNE: {}", p[1:]))
        ;;
    | "SKP":
        if p.len < 2
            -> `std.Err("SKP missing address")
        ;;
        match parselit(p[1])
        | `Register(n): b = `std.Some([0xe0 | (n & 0x0f), 0x9e])
        | _:
            -> `std.Err(std.fmt("invalid arguments to SKP: {}", p[1:]))
        ;;
    | "SKNP":
        if p.len < 2
            -> `std.Err("SKNP missing address")
        ;;
        match parselit(p[1])
        | `Register(n): b = `std.Some([0xe0 | (n & 0x0f), 0xa1])
        | _:
            -> `std.Err(std.fmt("invalid arguments to SKNP: {}", p[1:]))
        ;;
    | "LD":
        if p.len < 3
            -> `std.Err("LD missing arguments")
        ;;
        match (parselit(p[1]), parselit(p[2]))
        | (`Register(n), `Keypress): b = `std.Some([0xf0 | (n & 0x0f), 0x0a])
        | (`Register(m), `Number(n)): b = `std.Some([0x60 | (m & 0x0f), (n & 0xff)])
        | (`Register(m), `Register(n)): b = `std.Some([0x80 | (n & 0x0f), (m & 0x0f) << 4])
        | (`Register(n), `DelayTimer): b = `std.Some([0xf0 | (n & 0x0f), 0x07])
        | (`DelayTimer, `Register(n)): b = `std.Some([0xf0 | (n & 0x0f), 0x15])
        | (`SoundTimer, `Register(n)): b = `std.Some([0xf0 | (n & 0x0f), 0x18])
        | (`AddressRegister, `Number(n)): b = `std.Some([0xa0 | (n & 0x0f), (n & 0xff)])
        | (`AddressRegister, `Label(l)): b = `std.Some([0xa0, 0x00])
            mark = `std.Some(strdup(l))
        | (`DerefAddr, `Register(n)): b = `std.Some([0xf0 | (n & 0x0f), 0x55])
        | (`Register(n), `DerefAddr): b = `std.Some([0xf0 | (n & 0x0f), 0x65])
        | _:
            -> `std.Err(std.fmt("invalid arguments to LD: {}", p[1:]))
        ;;
    | "ADD":
        if p.len < 3
            -> `std.Err("ADD missing arguments")
        ;;
        match (parselit(p[1]), parselit(p[2]))
        | (`AddressRegister, `Register(n)): b = `std.Some([0xf0 | (n & 0x0f), 0x1e])
        | (`Register(m), `Number(n)): b = `std.Some([0x70 | (m & 0x0f), n & 0xff])
        | (`Register(m), `Register(n)): b = `std.Some([0x80 | (m & 0x0f), ((n & 0x0f) << 4) | 0x04])
        | _:
            -> `std.Err(std.fmt("invalid arguments to ADD: {}", p[1:]))
        ;;
    | "SUB":
        if p.len < 3
            -> `std.Err("SUB missing arguments")
        ;;
        match (parselit(p[1]), parselit(p[2]))
        | (`Register(m), `Register(n)): b = `std.Some([0x80 | (m & 0x0f), ((n & 0x0f) << 4) | 0x05])
        | _:
            -> `std.Err(std.fmt("invalid arguments to SUB: {}", p[1:]))
        ;;
    | "SUBN":
        if p.len < 3
            -> `std.Err("SUBN missing arguments")
        ;;
        match (parselit(p[1]), parselit(p[2]))
        | (`Register(m), `Register(n)): b = `std.Some([0x80 | (m & 0x0f), ((n & 0x0f) << 4) | 0x07])
        | _:
            -> `std.Err(std.fmt("invalid arguments to SUBN: {}", p[1:]))
        ;;
    | "OR":
        if p.len < 3
            -> `std.Err("OR missing arguments")
        ;;
        match (parselit(p[1]), parselit(p[2]))
        | (`Register(m), `Register(n)): b = `std.Some([0x80 | (m & 0x0f), ((n & 0x0f) << 4) | 0x01])
        | _:
            -> `std.Err(std.fmt("invalid arguments to OR: {}", p[1:]))
        ;;
    | "AND":
        if p.len < 3
            -> `std.Err("AND missing arguments")
        ;;
        match (parselit(p[1]), parselit(p[2]))
        | (`Register(m), `Register(n)): b = `std.Some([0x80 | (m & 0x0f), ((n & 0x0f) << 4) | 0x02])
        | _:
            -> `std.Err(std.fmt("invalid arguments to AND: {}", p[1:]))
        ;;
    | "XOR":
        if p.len < 3
            -> `std.Err("XOR missing arguments")
        ;;
        match (parselit(p[1]), parselit(p[2]))
        | (`Register(m), `Register(n)): b = `std.Some([0x80 | (m & 0x0f), ((n & 0x0f) << 4) | 0x03])
        | _:
            -> `std.Err(std.fmt("invalid arguments to XOR: {}", p[1:]))
        ;;
    | "SHR":
        if p.len < 2
            -> `std.Err("SHR missing arguments")
        ;;
        match parselit(p[1])
        | `Register(n): b = `std.Some([0x80 | (n & 0x0f), 0x06])
        | _:
            -> `std.Err(std.fmt("invalid arguments to SHR: {}", p[1:]))
        ;;
    | "SHL":
        if p.len < 2
            -> `std.Err("SHL missing arguments")
        ;;
        match parselit(p[1])
        | `Register(n): b = `std.Some([0x80 | (n & 0x0f), 0x0e])
        | _:
            -> `std.Err(std.fmt("invalid arguments to SHL: {}", p[1:]))
        ;;
    | "BCD":
        if p.len < 2
            -> `std.Err("BCD missing arguments")
        ;;
        match parselit(p[1])
        | `Register(n): `std.Some([0xf0 | (n & 0x0f), 0x33])
        | _:
            -> `std.Err(std.fmt("invalid arguments to BCD: {}", p[1:]))
        ;;
    | "RND":
        if p.len < 3
            -> `std.Err("RND missing arguments")
        ;;
        match (parselit(p[1]), parselit(p[2]))
        | (`Register(m), `Number(n)): b = `std.Some([0xc0 | (m & 0x0f), n & 0xff])
        | _:
            -> `std.Err(std.fmt("invalid arguments to RND: {}", p[1:]))
        ;;
    | "DRW":
        if p.len < 4
            -> `std.Err("DRW missing arguments")
        ;;
        match (parselit(p[1]), parselit(p[2]), parselit(p[3]))
        | (`Register(m), `Register(n), `Number(q)): b = `std.Some([0xd0 | (m & 0x0f), (n & 0x0f) << 4 | (q & 0x0f)])
        | _:
            -> `std.Err(std.fmt("invalid arguments to DRW: {}", p[1:]))
        ;;
    | _:
        -> `std.Err(std.fmt("unrecognized instruction {}", p[0]))
    ;;
	match upcase(p[0])
	| "CLS":
		b = `std.Some([0x00, 0xe0])
	| "RET":
		b = `std.Some([0x00, 0xee])
	| "SYS":
		if p.len < 2
			-> `std.Err("SYS missing subroutine address")
		;;
		match parselit(p[1])
		| `Number(n): b = `std.Some([0x00 | (n & 0x0f00), (n & 0xff)])
		| `Label(l): b = `std.Some([0x00, 0x00])
			mark = `std.Some(strdup(l))
		| _:
			-> `std.Err(std.fmt("invalid arguments to SYS: {}", p[1:]))
		;;
	| "CALL":
		if p.len < 2
			-> `std.Err("CALL missing subroutine address")
		;;
		match parselit(p[1])
		| `Number(n): b = `std.Some([0x20 | (n & 0x0f00), (n & 0xff)])
		| `Label(l): b = `std.Some([0x20, 0x00])
			mark = `std.Some(strdup(l))
		| _:
			-> `std.Err(std.fmt("invalid arguments to CALL: {}", p[1:]))
		;;
	| "JP":
		if p.len < 2
			-> `std.Err("JP missing address")
		elif p.len == 2
			match parselit(p[1])
			| `Number(n): b = `std.Some([0x10 | (n & 0x0f00), (n & 0xff)])
			| `Label(l): b = `std.Some([0x10, 0x00])
				mark = `std.Some(strdup(l))
			| _:
				-> `std.Err(std.fmt("invalid arguments to JP: {}", p[1:]))
			;;
		else
			match (parselit(p[1]), parselit(p[2]))
			| (`Register(0), `Number(n)):
				b = `std.Some([0xb0 | (n & 0x0f00), (n & 0xff)])
			| (`Register(0), `Label(l)): b = `std.Some([0xb0, 0x00])
				mark = `std.Some(strdup(l))
			| _:
				-> `std.Err(std.fmt("invalid arguments to JP: {}", p[1:]))
			;;
		;;
	| "SE":
		if p.len < 3
			-> `std.Err("SE missing arguments")
		;;
		match (parselit(p[1]), parselit(p[2]))
		| (`Register(m), `Number(n)):
			b = `std.Some([0x30 | (m & 0x0f), (n & 0xff)])
		| (`Register(m), `Register(n)):
			b = `std.Some([0x50 | (m & 0x0f), (n & 0x0f) << 4])
		| _:
			-> `std.Err(std.fmt("invalid arguments to SE: {}", p[1:]))
		;;
	| "SNE":
		if p.len < 3
			-> `std.Err("SNE missing arguments")
		;;
		match (parselit(p[1]), parselit(p[2]))
		| (`Register(m), `Number(n)):
			b = `std.Some([0x40 | (m & 0x0f), (n & 0xff)])
		| (`Register(m), `Register(n)):
			b = `std.Some([0x90 | (m & 0x0f), (n & 0x0f) << 4])
		| _:
			-> `std.Err(std.fmt("invalid arguments to SNE: {}", p[1:]))
		;;
	| "SKP":
		if p.len < 2
			-> `std.Err("SKP missing address")
		;;
		match parselit(p[1])
		| `Register(n): b = `std.Some([0xe0 | (n & 0x0f), 0x9e])
		| _:
			-> `std.Err(std.fmt("invalid arguments to SKP: {}", p[1:]))
		;;
	| "SKNP":
		if p.len < 2
			-> `std.Err("SKNP missing address")
		;;
		match parselit(p[1])
		| `Register(n): b = `std.Some([0xe0 | (n & 0x0f), 0xa1])
		| _:
			-> `std.Err(std.fmt("invalid arguments to SKNP: {}", p[1:]))
		;;
	| "LD":
		if p.len < 3
			-> `std.Err("LD missing arguments")
		;;
		match (parselit(p[1]), parselit(p[2]))
		| (`Register(n), `Keypress): b = `std.Some([0xf0 | (n & 0x0f), 0x0a])
		| (`Register(m), `Number(n)): b = `std.Some([0x60 | (m & 0x0f), (n & 0xff)])
		| (`Register(m), `Register(n)): b = `std.Some([0x80 | (n & 0x0f), (m & 0x0f) << 4])
		| (`Register(n), `DelayTimer): b = `std.Some([0xf0 | (n & 0x0f), 0x07])
		| (`DelayTimer, `Register(n)): b = `std.Some([0xf0 | (n & 0x0f), 0x15])
		| (`SoundTimer, `Register(n)): b = `std.Some([0xf0 | (n & 0x0f), 0x18])
		| (`AddressRegister, `Number(n)): b = `std.Some([0xa0 | (n & 0x0f), (n & 0xff)])
		| (`AddressRegister, `Label(l)): b = `std.Some([0xa0, 0x00])
			mark = `std.Some(strdup(l))
		| (`DerefAddr, `Register(n)): b = `std.Some([0xf0 | (n & 0x0f), 0x55])
		| (`Register(n), `DerefAddr): b = `std.Some([0xf0 | (n & 0x0f), 0x65])
		| _:
			-> `std.Err(std.fmt("invalid arguments to LD: {}", p[1:]))
		;;
	| "ADD":
		if p.len < 3
			-> `std.Err("ADD missing arguments")
		;;
		match (parselit(p[1]), parselit(p[2]))
		| (`AddressRegister, `Register(n)): b = `std.Some([0xf0 | (n & 0x0f), 0x1e])
		| (`Register(m), `Number(n)): b = `std.Some([0x70 | (m & 0x0f), n & 0xff])
		| (`Register(m), `Register(n)): b = `std.Some([0x80 | (m & 0x0f), ((n & 0x0f) << 4) | 0x04])
		| _:
			-> `std.Err(std.fmt("invalid arguments to ADD: {}", p[1:]))
		;;
	| "SUB":
		if p.len < 3
			-> `std.Err("SUB missing arguments")
		;;
		match (parselit(p[1]), parselit(p[2]))
		| (`Register(m), `Register(n)): b = `std.Some([0x80 | (m & 0x0f), ((n & 0x0f) << 4) | 0x05])
		| _:
			-> `std.Err(std.fmt("invalid arguments to SUB: {}", p[1:]))
		;;
	| "SUBN":
		if p.len < 3
			-> `std.Err("SUBN missing arguments")
		;;
		match (parselit(p[1]), parselit(p[2]))
		| (`Register(m), `Register(n)): b = `std.Some([0x80 | (m & 0x0f), ((n & 0x0f) << 4) | 0x07])
		| _:
			-> `std.Err(std.fmt("invalid arguments to SUBN: {}", p[1:]))
		;;
	| "OR":
		if p.len < 3
			-> `std.Err("OR missing arguments")
		;;
		match (parselit(p[1]), parselit(p[2]))
		| (`Register(m), `Register(n)): b = `std.Some([0x80 | (m & 0x0f), ((n & 0x0f) << 4) | 0x01])
		| _:
			-> `std.Err(std.fmt("invalid arguments to OR: {}", p[1:]))
		;;
	| "AND":
		if p.len < 3
			-> `std.Err("AND missing arguments")
		;;
		match (parselit(p[1]), parselit(p[2]))
		| (`Register(m), `Register(n)): b = `std.Some([0x80 | (m & 0x0f), ((n & 0x0f) << 4) | 0x02])
		| _:
			-> `std.Err(std.fmt("invalid arguments to AND: {}", p[1:]))
		;;
	| "XOR":
		if p.len < 3
			-> `std.Err("XOR missing arguments")
		;;
		match (parselit(p[1]), parselit(p[2]))
		| (`Register(m), `Register(n)): b = `std.Some([0x80 | (m & 0x0f), ((n & 0x0f) << 4) | 0x03])
		| _:
			-> `std.Err(std.fmt("invalid arguments to XOR: {}", p[1:]))
		;;
	| "SHR":
		if p.len < 2
			-> `std.Err("SHR missing arguments")
		;;
		match parselit(p[1])
		| `Register(n): b = `std.Some([0x80 | (n & 0x0f), 0x06])
		| _:
			-> `std.Err(std.fmt("invalid arguments to SHR: {}", p[1:]))
		;;
	| "SHL":
		if p.len < 2
			-> `std.Err("SHL missing arguments")
		;;
		match parselit(p[1])
		| `Register(n): b = `std.Some([0x80 | (n & 0x0f), 0x0e])
		| _:
			-> `std.Err(std.fmt("invalid arguments to SHL: {}", p[1:]))
		;;
	| "BCD":
		if p.len < 2
			-> `std.Err("BCD missing arguments")
		;;
		match parselit(p[1])
		| `Register(n): `std.Some([0xf0 | (n & 0x0f), 0x33])
		| _:
			-> `std.Err(std.fmt("invalid arguments to BCD: {}", p[1:]))
		;;
	| "RND":
		if p.len < 3
			-> `std.Err("RND missing arguments")
		;;
		match (parselit(p[1]), parselit(p[2]))
		| (`Register(m), `Number(n)): b = `std.Some([0xc0 | (m & 0x0f), n & 0xff])
		| _:
			-> `std.Err(std.fmt("invalid arguments to RND: {}", p[1:]))
		;;
	| "DRW":
		if p.len < 4
			-> `std.Err("DRW missing arguments")
		;;
		match (parselit(p[1]), parselit(p[2]), parselit(p[3]))
		| (`Register(m), `Register(n), `Number(q)): b = `std.Some([0xd0 | (m & 0x0f), (n & 0x0f) << 4 | (q & 0x0f)])
		| _:
			-> `std.Err(std.fmt("invalid arguments to DRW: {}", p[1:]))
		;;
	| _:
		-> `std.Err(std.fmt("unrecognized instruction {}", p[0]))
	;;

    -> `std.Ok((b, mark))
	-> `std.Ok((b, mark))
}

const die_emit = {msg, lc
    std.die(std.fmt("{} on line {}\n", msg, lc))
}

const die_rewrite = {l, lc
    const s = "ref to undefined label '{}' on line {}\n"
    std.die(std.fmt(s, l, lc))
}


/* convert `arr` to a byte[:] slice */
const itob = {arr
    var i
    var ret = std.slalloc(arr.len)
    for i = 0; i < arr.len; i++;
        ret[i] = ((arr[i] & 0xff) : byte)
    ;;
    -> ret
	var i
	var ret = std.slalloc(arr.len)
	for i = 0; i < arr.len; i++;
		ret[i] = ((arr[i] & 0xff) : byte)
	;;
	-> ret
}

const main = {
    var fd = bio.mkfile(std.In, bio.Rd)
    var src = bio.byline(fd)
    var lc = 0
	var fd = bio.mkfile(std.In, bio.Rd)
	var src = bio.byline(fd)
	var lc = 0

    var offset = 0
    var buf = [][:]
    var q = [][:]
    var labels = std.mkht()
    var res
	var offset = 0
	var buf = [][:]
	var q = [][:]
	var labels = std.mkht()
	var res

    for line : src ;
        match readline(line)
        | (`std.None, i): res = emitinstr(i)
        | (`std.Some (label), i): res = emitinstr(i)
            std.htput(labels, strdup(label), offset)
        ;;
	for line : src ;
		match readline(line)
		| (`std.None, i): res = emitinstr(i)
		| (`std.Some (label), i): res = emitinstr(i)
			std.htput(labels, strdup(label), offset)
		;;

        match res
        | `std.Err(msg): die_emit(msg, lc)
        | `std.Ok((bytes, marker)):
            match marker
            | `std.Some(label):
                q = std.slpush(&q, (label, offset, lc))
            | `std.None:
            ;;
            match bytes
            | `std.Some(arr):
                buf = std.sljoin(&buf, arr[:])
                offset += 2
            | `std.None:
            ;;
        ;;
		match res
		| `std.Err(msg): std.fatal("{} on line {}\n", msg, lc)
		| `std.Ok((bytes, marker)):
			match marker
			| `std.Some(label):
				q = std.slpush(&q, (label, offset, lc))
			| `std.None:
			;;
			match bytes
			| `std.Some(arr):
				buf = std.sljoin(&buf, arr[:])
				offset += 2
			| `std.None:
			;;
		;;

        lc++
    ;;
		lc++
	;;

    for p : q ;
        match p
        | (l, buf_pos, linum):
            match std.htget(labels, l)
            | `std.None: die_rewrite(l, linum)
            | `std.Some(addr):
                buf[buf_pos] |= ((addr + 0x200) & 0x0f00) >> 8
                buf[buf_pos + 1] |= (addr + 0x200) & 0xff
            ;;
        ;;
    ;;
	for p : q ;
		match p
		| (l, buf_pos, linum):
			match std.htget(labels, l)
			| `std.None: std.fatal("ref to undefined label '{}' on line {}\n", l, linum)
			| `std.Some(addr):
				buf[buf_pos] |= ((addr + 0x200) & 0x0f00) >> 8
				buf[buf_pos + 1] |= (addr + 0x200) & 0xff
			;;
		;;
	;;

    std.write(std.Out, itob(buf))
	std.write(std.Out, itob(buf))

    bio.free(fd)
	bio.free(fd)
}

M main.myr => main.myr +97 -11
@@ 24,7 24,7 @@ const loadprg = {b, fname
    match std.open(fname, std.Oread)
    | `std.Ok(n): fd = n
    | `std.Err(errno):
        std.die(std.fmt("could not open {}\n", fname))
        std.fatal("could not open {}\n", fname)
    ;;

    buf = std.slalloc(0xfff - 0x200)


@@ 34,7 34,7 @@ const loadprg = {b, fname
            b#[i + 0x200] = (buf[i] : uint8)
        ;;
    | `std.Err(n):
        std.die(std.fmt("could not read {}\n", fname))
        std.fatal("could not read {}\n", fname)
    ;;
}



@@ 61,13 61,35 @@ const main = {
    var sound : uint8 = 0

    clrscr(&gfx, scrsz)
    loadprg(&mem, "/home/jakob/Airplane.ch8")
    loadprg(&mem, "/tmp/UFO")

    var opcode, arg

    while true
        sdl.delay(1000)
        opcode = mem[pc]
        arg = mem[pc + 1]
        std.put("\x1b[H\x1b[2J")
        std.put("v0: {}\n", reg[0])
        std.put("v1: {}\n", reg[1])
        std.put("v2: {}\n", reg[2])
        std.put("v3: {}\n", reg[3])
        std.put("v4: {}\n", reg[4])
        std.put("v5: {}\n", reg[5])
        std.put("v6: {}\n", reg[6])
        std.put("v7: {}\n", reg[7])
        std.put("v8: {}\n", reg[8])
        std.put("v9: {}\n", reg[9])
        std.put("va: {}\n", reg[10])
        std.put("vb: {}\n", reg[11])
        std.put("vc: {}\n", reg[12])
        std.put("vd: {}\n", reg[13])
        std.put("ve: {}\n", reg[14])
        std.put("vf: {}\n", reg[15])
        std.put("\n")
        std.put("I: {}, d: {}, s: {}\n", I, delay, sound)
        std.put("sp: {}, stk: {}\n", sp, stk)
        std.put("{p=0,x}: {p=0,x} {p=0,x}\n", pc, opcode, arg)
        match (opcode & 0xf0) >> 4
        | 0x0:
            // CLS


@@ 82,23 104,25 @@ const main = {
                sp--
            // SYS
            else
                std.die("RCA 1802 SYS unimplemted\n")
                std.die("RCA 1802 SYS unimplemted")
            ;;
        // JP
        | 0x1:
            pc = (opcode & 0x0f : uint16)
            pc <<= 8
            pc |= (arg : uint16)
            pc -= 2
        // CALL
        | 0x2:
            sp++
            if sp >= stksz
                std.die("stack overflow\n")
                std.die("stack overflow")
            ;;
            stk[sp] = pc
            pc = (opcode & 0x0f : uint16)
            pc <<= 8
            pc |= (arg : uint16)
            pc -= 2
        // SE
        | 0x3:
            if reg[opcode & 0x0f] == arg


@@ 166,7 190,7 @@ const main = {
            | 0xe:
                reg[0xf] = reg[opcode & 0x0f] & (1 << 7)
                reg[opcode & 0x0f] <<= 1
            | _: std.die("unimplemented opcode\n")
            | _: std.die("unimplemented opcode")
            ;;
        // SNE
        | 0x9:


@@ 184,17 208,79 @@ const main = {
            pc <<= 8
            pc |= (arg : uint16)
            pc += (reg[0] : uint16)
            pc -= 2
        // RND
        | 0xc:
            reg[opcode & 0x0f] = std.rand(0, 256) & arg
        | _ : std.die("unimplemented opcode\n")
            // HACK: SIGFPE when calling std.rand(0, 256)
            reg[opcode & 0x0f] = (std.rand(0, 255) + std.rand(0, 2)) & arg
        // DRW
        | 0xd:
            var x = (reg[opcode & 0x0f] : uint16)
            var y = (reg[(arg & 0xf0) >> 8] : uint16)
            var n = (arg & 0x0f : uint16)
            var i, j
            for i = 0; i < n; i++;
                for j = 0; j < 8; j++
                    if (y + i) * scrwidth + x + j < scrsz
                        if mem[I + i * 8 + j] != 0
                            gfx[(y + i) * scrwidth + x + j] = 0xff
                        else
                            gfx[(y + i) * scrwidth + x + j] = 0x00
                        ;;
                    ;;
                ;;
            ;;
            sdl.update(tex, (gfx[:] : void#), 64)
            sdl.copy(r, tex)
            sdl.present(r)
        | 0xe:
            // SKP
            if arg == 0x9e
            // SKNP
            elif arg == 0xa1
                pc += 2
            else
                std.die("unimplemented opcode")
            ;;
        | 0xf:
            match arg
            | 0x07:
                reg[opcode & 0x0f] = delay
            | 0x0a:
                std.die("unimplemented opcode")
            | 0x15:
                delay = reg[opcode & 0x0f]
            | 0x18:
                sound = reg[opcode & 0x0f]
            | 0x1e:
                // TODO: Deal with overflow
                I += (reg[opcode & 0x0f] : uint16)
            | 0x29:
                // TODO
                I = 0
            | 0x33:
                // TODO
            | 0x55:
                // TODO
            | 0x65:
                // TODO
            | _:
                std.die("unimplemented opcode")
            ;;
        | _ : std.die("unimplemented opcode")
        ;;
        pc += 2
        if delay > 0
            delay--
        ;;
        if sound > 0
            sound--
        ;;
    ;;

    sdl.update(tex, (gfx[:] : void#), 64)
    sdl.copy(r, tex)
    sdl.present(r)
    /* sdl.update(tex, (gfx[:] : void#), 64) */
    /* sdl.copy(r, tex) */
    /* sdl.present(r) */

    sdl.freerenderer(r)
    sdl.freewin(win)