Index: .gitignore
===================================================================
--- .gitignore	(revision a06aa8be3631490d2ce602f681044034ba655137)
+++ .gitignore	(revision b9097777c78d15f0b8d2fda1a83dccb79f73e3de)
@@ -1,2 +1,3 @@
 build
 buchla
+bios.abs
Index: emu/all.h
===================================================================
--- emu/all.h	(revision a06aa8be3631490d2ce602f681044034ba655137)
+++ emu/all.h	(revision b9097777c78d15f0b8d2fda1a83dccb79f73e3de)
@@ -52,5 +52,5 @@
 extern void sdl_quit(void);
 
-extern void cpu_loop(void);
+extern void cpu_loop(const char *bios);
 
 extern void fpu_init(void);
Index: emu/cpu.c
===================================================================
--- emu/cpu.c	(revision a06aa8be3631490d2ce602f681044034ba655137)
+++ emu/cpu.c	(revision b9097777c78d15f0b8d2fda1a83dccb79f73e3de)
@@ -58,8 +58,8 @@
 static uint8_t rom_data[ROM_SIZE];
 
-static uint32_t ram_rd_beg;
-static uint32_t ram_rd_end;
-static uint32_t ram_wr_beg;
-static uint32_t ram_wr_end;
+static uint32_t ram_rd_beg = 0x10000000;
+static uint32_t ram_rd_end = 0x10000000;
+static uint32_t ram_wr_beg = 0x10000000;
+static uint32_t ram_wr_end = 0x10000000;
 
 static uint32_t rom_rd_beg;
@@ -94,4 +94,6 @@
 static void hw_init(void)
 {
+	ver("initializing hardware");
+
 	for (int32_t i = 0; i < ARRAY_COUNT(hw_map); ++i) {
 		hw_map[i].init();
@@ -113,4 +115,56 @@
 
 	return (addr - hw->addr_beg) / 2;
+}
+
+static void bios_init(const char *bios)
+{
+	ver("loading BIOS file %s", bios);
+
+	SDL_RWops *ops = SDL_RWFromFile(bios, "rb");
+
+	if (ops == NULL) {
+		fail("error while opening BIOS file %s", bios);
+	}
+
+	if (SDL_ReadBE16(ops) != 0x601b) {
+		fail("invalid BIOS file %s", bios);
+	}
+
+	uint32_t text_len = SDL_ReadBE32(ops);
+	uint32_t data_len = SDL_ReadBE32(ops);
+	uint32_t bss_len = SDL_ReadBE32(ops);
+
+	SDL_ReadBE32(ops);
+	SDL_ReadBE32(ops);
+
+	uint32_t text_loc = SDL_ReadBE32(ops);
+
+	SDL_ReadBE16(ops);
+
+	uint32_t data_loc = SDL_ReadBE32(ops);
+	uint32_t bss_loc = SDL_ReadBE32(ops);
+
+	ver("text 0x%x@0x%x data 0x%x@0x%x bss 0x%x@0x%x",
+			text_len, text_loc, data_len, data_loc, bss_len, bss_loc);
+
+	size_t load_len = (size_t)SDL_RWsize(ops) - 36;
+
+	if (load_len != text_len + data_len) {
+		fail("corrupted BIOS file %s", bios);
+	}
+
+	size_t loaded = 0;
+
+	while (loaded < load_len) {
+		size_t n_rd = SDL_RWread(ops, rom_data + loaded, 1, load_len - loaded);
+
+		if (n_rd == 0) {
+			fail("error while reading BIOS file %s", bios);
+		}
+
+		loaded += n_rd;
+	}
+
+	SDL_RWclose(ops);
 }
 
@@ -182,13 +236,14 @@
 	if (reset) {
 		if (addr == 0) {
-			return RESET_SP;
-		}
-
-		if (addr == 4) {
+			addr += ROM_START;
+		}
+
+		else if (addr == 4) {
+			addr += ROM_START;
 			reset = false;
-			return RESET_PC;
-		}
-
-		fail("invalid reset sequence");
+		}
+		else {
+			fail("invalid reset sequence");
+		}
 	}
 
@@ -301,8 +356,10 @@
 }
 
-void cpu_loop(void)
-{
-	ver("initializing hardware");
+void cpu_loop(const char *bios)
+{
+	ver("entering CPU loop");
+
 	hw_init();
+	bios_init(bios);
 
 	ver("starting CPU");
Index: emu/main.c
===================================================================
--- emu/main.c	(revision a06aa8be3631490d2ce602f681044034ba655137)
+++ emu/main.c	(revision b9097777c78d15f0b8d2fda1a83dccb79f73e3de)
@@ -18,13 +18,98 @@
 #include <all.h>
 
+typedef struct {
+	const char *name;
+	bool *flag;
+} verb_flag_t;
+
+static verb_flag_t verb_flags[] = {
+	{ "sdl", &sdl_verbose },
+	{ "cpu", &cpu_verbose },
+	{ "fpu", &fpu_verbose },
+	{ "vid", &vid_verbose },
+	{ "tim", &tim_verbose },
+	{ "lcd", &lcd_verbose },
+	{ "ser", &ser_verbose },
+	{ "mid", &mid_verbose },
+	{ "fdd", &fdd_verbose },
+	{ "snd", &snd_verbose },
+	{ "led", &led_verbose },
+	{ "kbd", &kbd_verbose }
+};
+
+static const char *bios = "bios.abs";
+
+static void usage(FILE *fh)
+{
+	fprintf(fh, "usage: buchla [-h] [-v comp [-v comp [...]]] [-b bios]\n");
+	fprintf(fh, "where comp is one of: ");
+
+	for (int32_t i = 0; i < ARRAY_COUNT(verb_flags); ++i) {
+		fprintf(fh, "%s, ", verb_flags[i].name);
+	}
+
+	fprintf(fh, "all\n");
+}
+
+static void parse_args(int32_t argc, char *argv[])
+{
+	for (int32_t i = 0; i < argc; ++i) {
+		if (strcmp(argv[i], "-h") == 0) {
+			usage(stdout);
+			exit(0);
+		}
+
+		if (strcmp(argv[i], "-b") == 0) {
+			if (++i == argc) {
+				usage(stderr);
+				fprintf(stderr, "missing argument to -b\n");
+				exit(1);
+			}
+
+			bios = argv[i];
+			continue;
+		}
+
+		if (strcmp(argv[i], "-v") == 0) {
+			if (++i == argc) {
+				usage(stderr);
+				fprintf(stderr, "missing argument to -v\n");
+				exit(1);
+			}
+
+			int32_t k;
+
+			if (strcmp(argv[i], "all") == 0) {
+				for (k = 0; k < ARRAY_COUNT(verb_flags); ++k) {
+					*verb_flags[k].flag = true;
+				}
+
+				continue;
+			}
+
+			for (k = 0; k < ARRAY_COUNT(verb_flags); ++k) {
+				if (strcmp(argv[i], verb_flags[k].name) == 0) {
+					*verb_flags[k].flag = true;
+					break;
+				}
+			}
+
+			if (k == ARRAY_COUNT(verb_flags)) {
+				usage(stderr);
+				fprintf(stderr, "invalid argument to -v: %s\n", argv[i]);
+				exit(1);
+			}
+
+			continue;
+		}
+	}
+}
+
 int32_t main(int32_t argc, char *argv[])
 {
-	(void)argc;
-	(void)argv;
-
+	parse_args(argc, argv);
 	sdl_init();
 
-	cpu_verbose = true;
-	cpu_loop();
+	cpu_loop(bios);
 
 	sdl_quit();
