/* test_host_rom_range.c -- the ROM is the machine's: read and run, never written. * * docs/v4.0.0/MACHINE.md section 2, DATASHEET-F18.md section 5. The ROM is a * read-only range at V4_ROM_BASE, above RAM. An instruction fetch, an @p * literal and a data fetch there read the ROM; a running programme's store * there is an address fault. Like every device in the model it is attached * by the node's owner, and a reset detaches it. */ #include "v4/asm.h" #include "v4/testcode.h" #include static int failures = 0, checks = 0; #define CHECK(c,...) do{checks++; if(!(c)){failures++; printf("FAIL %s:%d: ",__FILE__,__LINE__); printf(__VA_ARGS__); printf("\n");}}while(0) static v4_node n, scratch; static v4_exec_state es; static v4_heat h; static v4_cell rom[16]; /* ROM words 0..: "7 ;" at ROM+0, then a cell holding 42 at ROM+8 */ static void build_rom(void) { v4_asm ra; unsigned i; v4_node_reset(&scratch); v4_asm_begin(&ra, &scratch, 0); v4_asm_lit(&ra, 7); v4_asm_op(&ra, V4_OP_SEMI); CHECK(v4_asm_ok(&ra), "the ROM's code assembles"); for (i = 0; i < 16; i++) rom[i] = scratch.mem[i]; rom[8] = 42; } int main(void) { v4_asm as; long r; build_rom(); v4_node_reset(&n); v4_exec_reset(&es); v4_heat_reset(&h); CHECK(V4_ROM_BASE == (v4_cell)V4_NODE_WORDS, "the ROM starts where RAM ends"); CHECK(v4_node_load(&n, V4_ROM_BASE) == 0, "no ROM attached: nothing there"); v4_node_rom_attach(&n, rom, 16); CHECK(v4_node_load(&n, V4_ROM_BASE) == rom[0], "the ROM reads"); CHECK(v4_node_load(&n, V4_ROM_BASE + 16) == 0, "past the ROM's words: nothing"); v4_node_store(&n, V4_ROM_BASE, 12345); CHECK(v4_node_load(&n, V4_ROM_BASE) == rom[0] && n.faults == 0, "C code's store into the ROM does nothing and counts no fault (node.h)"); /* RAM 16: call the ROM's word, then return */ v4_asm_begin(&as, &n, 16); v4_asm_branch(&as, V4_OP_CALL, V4_ROM_BASE); v4_asm_op(&as, V4_OP_SEMI); CHECK(v4_asm_ok(&as), "a call into the ROM assembles"); r = v4_test_call(&n, &es, &h, 16, 100); CHECK(r > 0, "the call returns"); CHECK(n.ds.depth == 1 && n.ds.t == 7, "code in the ROM runs: depth %u T %ld", n.ds.depth, (long)n.ds.t); /* RAM 32: fetch the ROM's cell 8 through A */ v4_dstack_reset(&n.ds); v4_asm_begin(&as, &n, 32); v4_asm_lit(&as, V4_ROM_BASE + 8); v4_asm_op(&as, V4_OP_BANG_A); v4_asm_op(&as, V4_OP_FETCH_A); v4_asm_op(&as, V4_OP_SEMI); CHECK(v4_asm_ok(&as), "a fetch from the ROM assembles"); r = v4_test_call(&n, &es, &h, 32, 100); CHECK(r > 0 && n.ds.depth == 1 && n.ds.t == 42, "a data fetch reads the ROM: T %ld", (long)n.ds.t); /* RAM 48: store 99 into the ROM's cell 8 through B */ v4_dstack_reset(&n.ds); v4_asm_begin(&as, &n, 48); v4_asm_lit(&as, V4_ROM_BASE + 8); v4_asm_op(&as, V4_OP_BANG_B); v4_asm_lit(&as, 99); v4_asm_op(&as, V4_OP_STORE_B); v4_asm_op(&as, V4_OP_SEMI); CHECK(v4_asm_ok(&as), "a store into the ROM assembles"); r = v4_test_call(&n, &es, &h, 48, 100); CHECK(r < 0, "a store into the ROM does not return"); CHECK(n.fault_kind == V4_FAULT_ADDRESS && n.fault_addr == V4_ROM_BASE + 8, "it is an address fault at the ROM's address: kind %u addr %ld", n.fault_kind, (long)n.fault_addr); CHECK(v4_node_load(&n, V4_ROM_BASE + 8) == 42, "and the ROM is unchanged"); /* C code's store does nothing there either */ v4_node_store(&n, V4_ROM_BASE + 8, 99); CHECK(v4_node_load(&n, V4_ROM_BASE + 8) == 42, "v4_node_store leaves the ROM alone"); /* a reset detaches it, as it does every device */ v4_node_reset(&n); CHECK(v4_node_load(&n, V4_ROM_BASE) == 0, "a reset detaches the ROM"); v4_node_rom_attach(&n, rom, 16); CHECK(v4_node_load(&n, V4_ROM_BASE) == rom[0], "and the owner attaches it again"); /* more words than the range holds are refused: nothing attached */ v4_node_rom_attach(&n, rom, V4_ROM_WORDS + 1u); CHECK(v4_node_load(&n, V4_ROM_BASE) == 0, "a ROM larger than the range is not attached"); printf("test_host_rom_range: %d checks, %d failures\n", checks, failures); return failures != 0; }