~jakob/chip

a7a846114e43f6e058ecf83b84c2c58917db7886 — Jakob L. Kreuze 4 years ago b43bb07
I'm done with this.
3 files changed, 365 insertions(+), 289 deletions(-)

M main.myr
M sdl.glue.c
M sdl.myr
M main.myr => main.myr +318 -260
@@ 12,277 12,335 @@ const memsz = 4096
const stksz = 16
const regsz = 16

const fntoff = 0x50
const fntsz = 80
const fnt = [
	0xF0, 0x90, 0x90, 0x90, 0xF0, // 0
	0x20, 0x60, 0x20, 0x20, 0x70, // 1
	0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
	0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3
	0x90, 0x90, 0xF0, 0x10, 0x10, // 4
	0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5
	0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6
	0xF0, 0x10, 0x20, 0x40, 0x40, // 7
	0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8
	0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9
	0xF0, 0x90, 0xF0, 0x90, 0x90, // A
	0xE0, 0x90, 0xE0, 0x90, 0xE0, // B
	0xF0, 0x80, 0x80, 0x80, 0xF0, // C
	0xE0, 0x90, 0x90, 0x90, 0xE0, // D
	0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
	0xF0, 0x80, 0xF0, 0x80, 0x80  // F
];

const clrscr = {b, n
    var i
    for i = 0; i < n; i++;
        b#[i] = 0
    ;;
	var i
	for i = 0; i < n; i++;
		b#[i] = 0
	;;
}

const loadprg = {b, fname
    var fd, i, buf
    match std.open(fname, std.Oread)
    | `std.Ok(n): fd = n
    | `std.Err(errno):
        std.fatal("could not open {}\n", fname)
    ;;
	var fd, i, buf
	match std.open(fname, std.Oread)
	| `std.Ok(n): fd = n
	| `std.Err(errno):
		std.fatal("could not open {}\n", fname)
	;;

    buf = std.slalloc(0xfff - 0x200)
    match std.read(fd, buf)
    | `std.Ok(n):
        for i = 0; i < 0xfff - 0x200; i++;
            b#[i + 0x200] = (buf[i] : uint8)
        ;;
    | `std.Err(n):
        std.fatal("could not read {}\n", fname)
    ;;
	buf = std.slalloc(0xfff - 0x200)
	match std.read(fd, buf)
	| `std.Ok(n):
		for i = 0; i < 0xfff - 0x200; i++;
			b#[i + 0x200] = (buf[i] : uint8)
		;;
	| `std.Err(n):
		std.fatal("could not read {}\n", fname)
	;;
}

const main = {
    var win, r, tex
    sdl.init(sdl.INIT_VIDEO)
    win = sdl.mkwin(("chip\0" : byte#),
        sdl.WIN_POS_UNSPEC,
        sdl.WIN_POS_UNSPEC,
        winwidth,
        winheight,
        sdl.WIN_OPENGL)
    r = sdl.mkrenderer(win, -1, sdl.RENDERER_ACCEL)
    tex = sdl.mktexture(r, sdl.PIXFMT_RGB332, sdl.TEXACCESS_STREAM, 64, 32)
const loadfnt = {b
	var i
	for i = 0; i < fntsz; i++;
		b#[i+fntoff] = fnt[i]
	;;
}

    var gfx : uint8[scrsz]
    var mem : uint8[memsz]
    var reg : uint8[regsz]
    var stk : uint16[stksz]
    var pc : uint16 = 0x200
    var sp : uint16 = 0
    var I : uint16 = 0
    var delay : uint8 = 0
    var sound : uint8 = 0
const getkeys = {
	var state = sdl.getkbd()
	-> [
		state#[sdl.SCANCODE_1],
		state#[sdl.SCANCODE_2],
		state#[sdl.SCANCODE_3],
		state#[sdl.SCANCODE_4],
		state#[sdl.SCANCODE_Q],
		state#[sdl.SCANCODE_W],
		state#[sdl.SCANCODE_E],
		state#[sdl.SCANCODE_R],
		state#[sdl.SCANCODE_A],
		state#[sdl.SCANCODE_S],
		state#[sdl.SCANCODE_D],
		state#[sdl.SCANCODE_F],
		state#[sdl.SCANCODE_Z],
		state#[sdl.SCANCODE_X],
		state#[sdl.SCANCODE_C],
		state#[sdl.SCANCODE_V],
		state#[sdl.SCANCODE_ESC],
	]
}

const main = {
	var win, r, tex
	sdl.init(sdl.INIT_VIDEO)
	win = sdl.mkwin(("chip\0" : byte#),
		sdl.WIN_POS_UNSPEC,
		sdl.WIN_POS_UNSPEC,
		winwidth,
		winheight,
		sdl.WIN_OPENGL)
	r = sdl.mkrenderer(win, -1, sdl.RENDERER_ACCEL)
	tex = sdl.mktexture(r, sdl.PIXFMT_RGB332, sdl.TEXACCESS_STREAM, 64, 32)

    clrscr(&gfx, scrsz)
    loadprg(&mem, "/tmp/UFO")
	var gfx : uint8[scrsz]
	var mem : uint8[memsz]
	var reg : uint8[regsz]
	var stk : uint16[stksz]
	var pc : uint16 = 0x200
	var sp : uint16 = 0
	var I : uint16 = 0
	var delay : uint8 = 0
	var sound : uint8 = 0
	var keys

    var opcode, arg
	clrscr(&gfx, scrsz)
	loadprg(&mem, "/tmp/UFO")
	loadfnt(&mem)

    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
            if (opcode & 0x0f) == 0 && (arg & 0x0f) == 0
                clrscr(&gfx, scrsz)
            // RET
            elif (opcode & 0x0f) == 0
                if sp == 0
                    std.die("stack underflow")
                ;;
                pc = stk[sp]
                sp--
            // SYS
            else
                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")
            ;;
            stk[sp] = pc
            pc = (opcode & 0x0f : uint16)
            pc <<= 8
            pc |= (arg : uint16)
            pc -= 2
        // SE
        | 0x3:
            if reg[opcode & 0x0f] == arg
                pc += 2
            ;;
        // SNE
        | 0x4:
            if reg[opcode & 0x0f] != arg
                pc += 2
            ;;
        // SE
        | 0x5:
            if reg[opcode & 0x0f] == reg[(arg & 0xf0) >> 4]
                pc += 2
            ;;
        // LD
        | 0x6:
            reg[opcode & 0x0f] = arg
        // ADD (without overflow)
        | 0x7:
            reg[opcode & 0x0f] += arg
        | 0x8:
            match arg & 0x0f
            // LD
            | 0x0:
                reg[opcode & 0x0f] = reg[(arg & 0xf0) >> 8]
            // OR
            | 0x1:
                reg[opcode & 0x0f] |= reg[(arg & 0xf0) >> 8]
            // AND
            | 0x2:
                reg[opcode & 0x0f] &= reg[(arg & 0xf0) >> 8]
            // XOR
            | 0x3:
                reg[opcode & 0x0f] ^= reg[(arg & 0xf0) >> 8]
            // ADD
            | 0x4:
                if (0xff - reg[opcode & 0x0f]) < reg[(arg & 0xf0) >> 8]
                    reg[0xf] = 1
                else
                    reg[0xf] = 0
                ;;
                reg[opcode & 0x0f] += reg[(arg & 0xf0) >> 8]
            // SUB
            | 0x5:
                if (0xff - reg[opcode & 0x0f]) < reg[(arg & 0xf0) >> 8]
                    reg[0xf] = 1
                else
                    reg[0xf] = 0
                ;;
                reg[opcode & 0x0f] -= reg[(arg & 0xf0) >> 8]
            // SHR
            | 0x6:
                reg[0xf] = reg[opcode & 0x0f] & 1
                reg[opcode & 0x0f] >>= 1
            // SUBN
            | 0x7:
                if (0xff - reg[(arg & 0xf0) >> 8]) < reg[opcode & 0x0f]
                    reg[0xf] = 1
                else
                    reg[0xf] = 0
                ;;
                reg[opcode & 0x0f] = reg[(arg & 0xf0) >> 8] - reg[opcode & 0x0f]
            // SHL
            | 0xe:
                reg[0xf] = reg[opcode & 0x0f] & (1 << 7)
                reg[opcode & 0x0f] <<= 1
            | _: std.die("unimplemented opcode")
            ;;
        // SNE
        | 0x9:
            if reg[opcode & 0x0f] != reg[(arg & 0xf0) >> 4]
                pc += 2
            ;;
        // LD (I)
        | 0xa:
            I = (opcode & 0x0f : uint16)
            I <<= 8
            I |= (arg : uint16)
        // JP + V0
        | 0xb:
            pc = (opcode & 0x0f : uint16)
            pc <<= 8
            pc |= (arg : uint16)
            pc += (reg[0] : uint16)
            pc -= 2
        // RND
        | 0xc:
            // 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--
        ;;
    ;;
	var opcode, arg

    /* sdl.update(tex, (gfx[:] : void#), 64) */
    /* sdl.copy(r, tex) */
    /* sdl.present(r) */
	while true
		opcode = mem[pc]
		arg = mem[pc + 1]
		keys = getkeys()
		sdl.delay(2)
		if keys[0x10] != 0
			break
		;;
		match (opcode & 0xf0) >> 4
		| 0x0:
			// CLS
			if (opcode & 0x0f) == 0 && (arg & 0x0f) == 0
				clrscr(&gfx, scrsz)
			// RET
			elif (opcode & 0x0f) == 0
				if sp == 0
					std.die("stack underflow")
				;;
				sp--
				pc = stk[sp]
			// SYS
			else
				std.die("RCA 1802 SYS unimplented")
			;;
		// JP
		| 0x1:
			pc = (opcode & 0x0f : uint16)
			pc <<= 8
			pc |= (arg : uint16)
			pc -= 2
		// CALL
		| 0x2:
			if sp >= stksz
				std.die("stack overflow")
			;;
			stk[sp] = pc
			sp++
			pc = (opcode & 0x0f : uint16)
			pc <<= 8
			pc |= (arg : uint16)
			pc -= 2
		// SE
		| 0x3:
			if reg[opcode & 0x0f] == arg
				pc += 2
			;;
		// SNE
		| 0x4:
			if reg[opcode & 0x0f] != arg
				pc += 2
			;;
		// SE
		| 0x5:
			if reg[opcode & 0x0f] == reg[(arg & 0xf0) >> 4]
				pc += 2
			;;
		// LD
		| 0x6:
			reg[opcode & 0x0f] = arg
		// ADD (without overflow)
		| 0x7:
			reg[opcode & 0x0f] += arg
		| 0x8:
			match arg & 0x0f
			// LD
			| 0x0:
				reg[opcode & 0x0f] = reg[(arg & 0xf0) >> 4]
			// OR
			| 0x1:
				reg[opcode & 0x0f] |= reg[(arg & 0xf0) >> 4]
			// AND
			| 0x2:
				reg[opcode & 0x0f] &= reg[(arg & 0xf0) >> 4]
			// XOR
			| 0x3:
				reg[opcode & 0x0f] ^= reg[(arg & 0xf0) >> 4]
			// ADD
			| 0x4:
				if (0xff - reg[opcode & 0x0f]) < reg[(arg & 0xf0) >> 4]
					reg[0xf] = 1
				else
					reg[0xf] = 0
				;;
				reg[opcode & 0x0f] += reg[(arg & 0xf0) >> 4]
			// SUB
			| 0x5:
				if (0xff - reg[opcode & 0x0f]) < reg[(arg & 0xf0) >> 4]
					reg[0xf] = 1
				else
					reg[0xf] = 0
				;;
				reg[opcode & 0x0f] -= reg[(arg & 0xf0) >> 4]
			// SHR
			| 0x6:
				reg[0xf] = reg[opcode & 0x0f] & 1
				reg[opcode & 0x0f] >>= 1
			// SUBN
			| 0x7:
				if (0xff - reg[(arg & 0xf0) >> 4]) < reg[opcode & 0x0f]
					reg[0xf] = 1
				else
					reg[0xf] = 0
				;;
				reg[opcode & 0x0f] = reg[(arg & 0xf0) >> 4] - reg[opcode & 0x0f]
			// SHL
			| 0xe:
				reg[0xf] = reg[opcode & 0x0f] & (1 << 7)
				reg[opcode & 0x0f] <<= 1
			| _: std.die("unimplemented opcode")
			;;
		// SNE
		| 0x9:
			if reg[opcode & 0x0f] != reg[(arg & 0xf0) >> 4]
				pc += 2
			;;
		// LD (I)
		| 0xa:
			I = (opcode & 0x0f : uint16)
			I <<= 8
			I |= (arg : uint16)
		// JP + V0
		| 0xb:
			pc = (opcode & 0x0f : uint16)
			pc <<= 8
			pc |= (arg : uint16)
			pc += (reg[0] : uint16)
			pc -= 2
		// RND
		| 0xc:
			// 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) >> 4] : uint16)
			var n = (arg & 0x0f : uint16)
			var i, j
			reg[0xf] = 0
			for i = 0; i < n; i++;
				for j = 0; j < 8; j++;
					if (y + i) * scrwidth + x + j < scrsz
						if mem[I + i] & ((0x80 >> j) : uint8) != 0
							if gfx[(y + i) * scrwidth + x + j] != 0
								reg[0xf] = 1
							;;
							gfx[(y + i) * scrwidth + x + j] ^= 0xff
						;;
					;;
				;;
			;;
			sdl.update(tex, (gfx[:] : void#), 64)
			sdl.copy(r, tex)
			sdl.present(r)
		| 0xe:
			// SKP
			if arg == 0x9e
				if keys[reg[opcode & 0x0f]] != 0
					pc += 2
				;;
			// SKNP
			elif arg == 0xa1
				if keys[reg[opcode & 0x0f]] == 0
					pc += 2
				;;
			else
				std.die("unimplemented opcode")
			;;
		| 0xf:
			match arg
			// LD
			| 0x07:
				reg[opcode & 0x0f] = delay
			// LD
			| 0x0a:
				std.die("unimplemented opcode")
			// LD
			| 0x15:
				delay = reg[opcode & 0x0f]
			// LD
			| 0x18:
				sound = reg[opcode & 0x0f]
			// ADD
			| 0x1e:
				I += (reg[opcode & 0x0f] : uint16)
				if I > 0xfff
					reg[0xf] = 1
				;;
			// LD
			| 0x29:
				I = fntoff + 5 * (reg[opcode & 0x0f] : uint16)
			// BCD
			| 0x33:
				mem[I] = reg[(opcode & 0x0f)] / 100
				mem[I + 1] = (reg[(opcode & 0x0f)] % 100) / 10
				// HACK: Assembler error on (opcode & 0x0f) % 10
				mem[I + 2] = reg[(opcode & 0x0f)] - mem[I + 1] * 10 - mem[I] * 100
			// LD
			| 0x55:
				var i
				for i = 0; i <= ((opcode & 0x0f) : uint16); i++;
					mem[I + i] = reg[i]
				;;
			// LD
			| 0x65:
				var i
				for i = 0; i <= ((opcode & 0x0f) : uint16); i++;
					reg[i] = mem[I + i]
				;;
			| _:
				std.die("unimplemented opcode")
			;;
		| _ : std.die("unimplemented opcode")
		;;
		pc += 2
		if delay > 0
			delay--
		;;
		if sound > 0
			sound--
		;;
	;;

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

M sdl.glue.c => sdl.glue.c +5 -7
@@ 64,10 64,8 @@ void sdl$delay(uint32_t ms)
		SDL_Delay(ms);
}

// SDL_GetKeyboardState
// SDL_SCANCODE_{}

// 1 2 3 C                                   1 2 3 4
// 4 5 6 D    This is emulated with these    Q W E R
// 7 8 9 E    keyboard keys -->              A S D F
// A 0 B F                                   Z X C V
const uint8_t *sdl$getkbd(void)
{
		SDL_PumpEvents();
		return SDL_GetKeyboardState(NULL);
}

M sdl.myr => sdl.myr +42 -22
@@ 1,36 1,56 @@
use std

pkg sdl =
    const INIT_VIDEO : uint32 = 32
    
    extern const init : (flags : uint32 -> int)
    extern const quit : (-> void)
	const INIT_VIDEO : uint32 = 32

    type win = void#
	extern const init : (flags : uint32 -> int)
	extern const quit : (-> void)

    const WIN_POS_UNSPEC : int = 536805376
    const WIN_OPENGL : uint32 = 2
	type win = void#

    extern const mkwin : (title : byte#, x : int, y : int, w : int, h : int, flags : uint32 -> win)
    extern const freewin : (win : win -> void)
	const WIN_POS_UNSPEC : int = 536805376
	const WIN_OPENGL : uint32 = 2

    type renderer = void#
	extern const mkwin : (title : byte#, x : int, y : int, w : int, h : int, flags : uint32 -> win)
	extern const freewin : (win : win -> void)

    const RENDERER_ACCEL : uint32 = 2
	type renderer = void#

    extern const mkrenderer : (win : win, index : int, flags: uint32 -> renderer)
    extern const copy : (r : renderer, tex : texture -> int)
    extern const present : (r : renderer -> void)
    extern const freerenderer : (r : renderer -> void)
	const RENDERER_ACCEL : uint32 = 2

    type texture = void#
	extern const mkrenderer : (win : win, index : int, flags: uint32 -> renderer)
	extern const copy : (r : renderer, tex : texture -> int)
	extern const present : (r : renderer -> void)
	extern const freerenderer : (r : renderer -> void)

    const PIXFMT_RGB332 : uint32 = 336660481
    const TEXACCESS_STREAM : int = 1
	type texture = void#

    extern const mktexture : (r : renderer, fmt : uint32, access : int, w : int, h : int -> texture)
    extern const update : (tex : texture, pixels : void#, pitch : int -> int)
    extern const freetexture : (tex : texture -> void)
	const PIXFMT_RGB332 : uint32 = 336660481
	const TEXACCESS_STREAM : int = 1

    extern const delay : (ms : uint32 -> void)
	extern const mktexture : (r : renderer, fmt : uint32, access : int, w : int, h : int -> texture)
	extern const update : (tex : texture, pixels : void#, pitch : int -> int)
	extern const freetexture : (tex : texture -> void)

	extern const delay : (ms : uint32 -> void)

	const SCANCODE_1 : uint8 = 30
	const SCANCODE_2 : uint8 = 31
	const SCANCODE_3 : uint8 = 32
	const SCANCODE_4 : uint8 = 33
	const SCANCODE_Q : uint8 = 20
	const SCANCODE_W : uint8 = 26
	const SCANCODE_E : uint8 = 8
	const SCANCODE_R : uint8 = 21
	const SCANCODE_A : uint8 = 4
	const SCANCODE_S : uint8 = 22
	const SCANCODE_D : uint8 = 7
	const SCANCODE_F : uint8 = 9
	const SCANCODE_Z : uint8 = 29
	const SCANCODE_X : uint8 = 27
	const SCANCODE_C : uint8 = 6
	const SCANCODE_V : uint8 = 25
	const SCANCODE_ESC : uint8 = 41

	extern const getkbd : ( -> uint8[256]#)
;;