UNPKG

@asm80/core

Version:

Core ASM80 compiler / assembler

538 lines (472 loc) 20.1 kB
import {I8008} from "../cpu/i8008.js"; import { Parser } from "../expression-parser.js"; QUnit.config.hidepassed = true; QUnit.module("ASM I8008"); QUnit.test( "Namespace", function() { QUnit.assert.notEqual( I8008, null, "I8008 is defined" ); QUnit.assert.equal( typeof(I8008), "object", "I8008 is an object" ); QUnit.assert.equal( typeof(I8008.parseOpcode), "function", "I8008.parseOpcode defined" ); }); //QUnit.module("Simple OP tests"); var vars = {"LOOP":0x1234,"SHORT":0x21,"_PC":0x0100}; var s = [], p; QUnit.test( "Invalid instruction", function() { s = {"opcode":"INVALID","params":["A","B"],"addr":0x100,"lens":[],"bytes":0}; p = I8008.parseOpcode(s, vars, Parser); QUnit.assert.equal(p,null,"Error detected"); }); QUnit.test( "NOP test", function() { s = {"opcode":"NOP","addr":0x100,"lens":[],"bytes":0}; p = I8008.parseOpcode(s, vars, Parser); QUnit.assert.equal(p.lens[0],0xc0,"Opcode OK"); QUnit.assert.equal(p.bytes,1,"Length OK"); }); QUnit.test( "RST7 test", function() { s = {"opcode":"RST","params":["7"],"addr":0x100,"lens":[],"bytes":0}; p = I8008.parseOpcode(s, vars, Parser); QUnit.assert.equal(p.lens[0],0x3d,"Opcode OK"); QUnit.assert.equal(p.bytes,1,"Length OK"); }); QUnit.test( "INP7 test", function() { s = {"opcode":"INP","params":["7"],"addr":0x100,"lens":[],"bytes":0}; p = I8008.parseOpcode(s, vars, Parser); QUnit.assert.equal(p.lens[0],0x4f,"Opcode OK"); QUnit.assert.equal(p.bytes,1,"Length OK"); }); QUnit.test( "OUT $1f test", function() { s = {"opcode":"OUT","params":["$1F"],"addr":0x100,"lens":[],"bytes":0}; p = I8008.parseOpcode(s, vars, Parser); QUnit.assert.equal(p.lens[0],0x7f,"Opcode OK"); QUnit.assert.equal(p.bytes,1,"Length OK"); }); QUnit.test( "LLI $1f test", function() { s = {"opcode":"LLI","params":["$1F"],"addr":0x100,"lens":[],"bytes":0}; p = I8008.parseOpcode(s, vars, Parser); QUnit.assert.equal(p.lens[0],0x36,"Opcode OK"); QUnit.assert.equal(typeof(p.lens[1]),"function","Opcode"); QUnit.assert.equal(p.bytes,2,"Length OK"); }); QUnit.test( "JMP", function() { s = {"opcode":"JMP","params":["$1234"],addr:"0x100",lens:[],"bytes":0}; p = I8008.parseOpcode(s, vars, Parser); QUnit.assert.equal(p.lens[0],0x44,"Opcode"); QUnit.assert.equal(typeof(p.lens[1]),"function","Opcode"); QUnit.assert.equal(p.bytes,3,"Length"); }); QUnit.test( "MOV test", function() { s = {"opcode":"MOV","params":["A","B"],"addr":0x100,"lens":[],"bytes":0}; p = I8008.parseOpcode(s, vars, Parser); QUnit.assert.equal(p.lens[0],0xc1,"Opcode OK"); QUnit.assert.equal(p.bytes,1,"Length OK"); }); QUnit.test( "CPE test 1", function() { s = {"opcode":"CPE","params":["$1234"],"addr":0x100,"lens":[],"bytes":0}; p = I8008.parseOpcode(s, vars, Parser); QUnit.assert.equal(p.lens[0],0x7a,"Opcode OK"); QUnit.assert.equal(typeof(p.lens[1]),"function","Opcode"); QUnit.assert.equal(p.bytes,3,"Length OK"); }); QUnit.test( "CPE test 2", function() { s = {"opcode":"CPE","params":[],"addr":0x100,"lens":[],"bytes":0}; p = I8008.parseOpcode(s, vars, Parser); QUnit.assert.equal(p.lens[0],0xbc,"Opcode OK"); QUnit.assert.equal(p.bytes,1,"Length OK"); }); QUnit.test( "XRA test 1", function() { s = {"opcode":"XRA","params":["B"],"addr":0x100,"lens":[],"bytes":0}; p = I8008.parseOpcode(s, vars, Parser); QUnit.assert.equal(p.lens[0],0xa9,"Opcode OK"); QUnit.assert.equal(p.bytes,1,"Length OK"); }); QUnit.test( "XRA test 2", function() { s = {"opcode":"XRA","params":[],"addr":0x100,"lens":[],"bytes":0}; p = I8008.parseOpcode(s, vars, Parser); QUnit.assert.equal(p.lens[0],0xa8,"Opcode OK"); QUnit.assert.equal(p.bytes,1,"Length OK"); }); QUnit.test( "ORA test 1", function() { s = {"opcode":"ORA","params":["B"],"addr":0x100,"lens":[],"bytes":0}; p = I8008.parseOpcode(s, vars, Parser); QUnit.assert.equal(p.lens[0],0xb1,"Opcode OK"); QUnit.assert.equal(p.bytes,1,"Length OK"); }); QUnit.test( "ORA test 2", function() { s = {"opcode":"ORA","params":[],"addr":0x100,"lens":[],"bytes":0}; p = I8008.parseOpcode(s, vars, Parser); QUnit.assert.equal(p.lens[0],0xb0,"Opcode OK"); QUnit.assert.equal(p.bytes,1,"Length OK"); }); QUnit.test( "ADC test 1", function() { s = {"opcode":"ADC","params":["B"],"addr":0x100,"lens":[],"bytes":0}; p = I8008.parseOpcode(s, vars, Parser); QUnit.assert.equal(p.lens[0],0x89,"Opcode OK"); QUnit.assert.equal(p.bytes,1,"Length OK"); }); QUnit.test( "ADC test 2", function() { s = {"opcode":"ADC","params":[],"addr":0x100,"lens":[],"bytes":0}; p = I8008.parseOpcode(s, vars, Parser); QUnit.assert.equal(p.lens[0],0x82,"Opcode OK"); QUnit.assert.equal(p.bytes,1,"Length OK"); }); QUnit.test( "INR test - increment register", function() { s = {"opcode":"INR","params":["B"],"addr":0x100,"lens":[],"bytes":0}; p = I8008.parseOpcode(s, vars, Parser); QUnit.assert.equal(p.lens[0],0x08,"Opcode OK"); QUnit.assert.equal(p.bytes,1,"Length OK"); }); QUnit.test( "INR test - cannot use A register", function() { try { s = {"opcode":"INR","params":["A"],"addr":0x100,"lens":[],"bytes":0}; p = I8008.parseOpcode(s, vars, Parser); } catch (e) { p = e; } QUnit.assert.equal(p,"Cannot use A register here","Error detected"); }); QUnit.test( "DCR test - decrement register", function() { s = {"opcode":"DCR","params":["C"],"addr":0x100,"lens":[],"bytes":0}; p = I8008.parseOpcode(s, vars, Parser); QUnit.assert.equal(p.lens[0],0x11,"Opcode OK"); QUnit.assert.equal(p.bytes,1,"Length OK"); }); QUnit.test( "MVI test - move immediate", function() { s = {"opcode":"MVI","params":["B","$42"],"addr":0x100,"lens":[],"bytes":0}; p = I8008.parseOpcode(s, vars, Parser); QUnit.assert.equal(p.lens[0],0x0e,"Opcode OK"); QUnit.assert.equal(typeof(p.lens[1]),"function","Function OK"); QUnit.assert.equal(p.bytes,2,"Length OK"); var par = p.lens[1]({}); QUnit.assert.equal(par,0x42,"Param OK"); }); QUnit.test( "Unknown register error in RR function", function() { try { s = {"opcode":"DCR","params":["X"],"addr":0x100,"lens":[],"bytes":0}; p = I8008.parseOpcode(s, vars, Parser); } catch (e) { p = e; } QUnit.assert.equal(p,"Unknown register X","Error detected"); }); QUnit.test( "Unknown register error in RR- function", function() { try { s = {"opcode":"INR","params":["Z"],"addr":0x100,"lens":[],"bytes":0}; p = I8008.parseOpcode(s, vars, Parser); } catch (e) { p = e; } QUnit.assert.equal(p,"Unknown register Z","Error detected"); }); QUnit.test( "Unknown register error in RB function", function() { try { s = {"opcode":"MVI","params":["Q","$10"],"addr":0x100,"lens":[],"bytes":0}; p = I8008.parseOpcode(s, vars, Parser); } catch (e) { p = e; } QUnit.assert.equal(p,"Unknown register Q","Error detected"); }); QUnit.test( "Missing second register in MOV", function() { try { s = {"opcode":"MOV","params":["A"],"addr":0x100,"lens":[],"bytes":0}; p = I8008.parseOpcode(s, vars, Parser); } catch (e) { p = e; } QUnit.assert.equal(p,"Missing second register","Error detected"); }); QUnit.test( "Unknown second register in MOV", function() { try { s = {"opcode":"MOV","params":["A","Q"],"addr":0x100,"lens":[],"bytes":0}; p = I8008.parseOpcode(s, vars, Parser); } catch (e) { p = e; } QUnit.assert.equal(p,"Unknown register Q","Error detected"); }); QUnit.test( "INP address out of range - negative", function() { try { s = {"opcode":"INP","params":["-1"],"addr":0x100,"lens":[],"bytes":0}; p = I8008.parseOpcode(s, vars, Parser); } catch (e) { p = e; } QUnit.assert.equal(p,"INP address out of limit (0-7): -1","Error detected"); }); QUnit.test( "INP address out of range - too high", function() { try { s = {"opcode":"INP","params":["8"],"addr":0x100,"lens":[],"bytes":0}; p = I8008.parseOpcode(s, vars, Parser); } catch (e) { p = e; } QUnit.assert.equal(p,"INP address out of limit (0-7): 8","Error detected"); }); QUnit.test( "OUT address out of range - too low", function() { try { s = {"opcode":"OUT","params":["7"],"addr":0x100,"lens":[],"bytes":0}; p = I8008.parseOpcode(s, vars, Parser); } catch (e) { p = e; } QUnit.assert.equal(p,"OUT address out of limit (8-31): 7","Error detected"); }); QUnit.test( "OUT address out of range - too high", function() { try { s = {"opcode":"OUT","params":["32"],"addr":0x100,"lens":[],"bytes":0}; p = I8008.parseOpcode(s, vars, Parser); } catch (e) { p = e; } QUnit.assert.equal(p,"OUT address out of limit (8-31): 32","Error detected"); }); QUnit.test( "Endian property", function() { QUnit.assert.equal(I8008.endian, false, "I8008 is little-endian"); }); QUnit.test( "CPU property", function() { QUnit.assert.equal(I8008.cpu, "i8008", "CPU identifier correct"); }); QUnit.test( "Extension property", function() { QUnit.assert.equal(I8008.ext, "a08", "File extension correct"); }); // Tests for RDD function (lines 286-288) QUnit.test( "RDD register test - valid registers", function() { var rdd = I8008.lens.RDD; QUnit.assert.equal(rdd("B"), 0, "B register index correct"); QUnit.assert.equal(rdd("D"), 1, "D register index correct"); QUnit.assert.equal(rdd("H"), 2, "H register index correct"); QUnit.assert.equal(rdd("S"), 3, "S register index correct"); QUnit.assert.equal(rdd("P"), 4, "P register index correct"); }); // Tests for RBD function (lines 289-291) QUnit.test( "RBD register test - valid registers", function() { var rbd = I8008.lens.RBD; QUnit.assert.equal(rbd("B"), 0, "B register index correct"); QUnit.assert.equal(rbd("D"), 1, "D register index correct"); }); // Tests for RQQ function (lines 292-294) QUnit.test( "RQQ register test - valid registers", function() { var rqq = I8008.lens.RQQ; QUnit.assert.equal(rqq("B"), 0, "B register index correct"); QUnit.assert.equal(rqq("D"), 1, "D register index correct"); QUnit.assert.equal(rqq("H"), 2, "H register index correct"); QUnit.assert.equal(rqq("P"), 3, "P register index correct"); QUnit.assert.equal(rqq("S"), 4, "S register index correct"); QUnit.assert.equal(rqq("W"), 5, "W register index correct"); }); QUnit.test( "RR0 function test", function() { s = {"opcode":"ADD","params":["A"],"addr":0x100,"lens":[],"bytes":0}; p = I8008.parseOpcode(s, vars, Parser); QUnit.assert.equal(p.lens[0],0x80,"Opcode OK"); QUnit.assert.equal(p.bytes,1,"Length OK"); }); QUnit.test( "RR0 bad register", function() { try { s = {"opcode":"ADD","params":["X"],"addr":0x100,"lens":[],"bytes":0}; p = I8008.parseOpcode(s, vars, Parser); } catch (e) { p = e; } QUnit.assert.equal(p,"Unknown register X","Error detected"); }); QUnit.test( "RRR bad register", function() { try { s = {"opcode":"MOV","params":["X","A"],"addr":0x100,"lens":[],"bytes":0}; p = I8008.parseOpcode(s, vars, Parser); } catch (e) { p = e; } QUnit.assert.equal(p,"Unknown register X","Error detected"); }); // Test to cover RDD function usage (lines 286-288) - I8008 doesn't have INX, use proper test QUnit.test( "RDD function usage test", function() { // Direct test of RDD function var rdd = I8008.lens.RDD; QUnit.assert.equal(rdd("B"), 0, "B register RDD test"); QUnit.assert.equal(rdd("D"), 1, "D register RDD test"); QUnit.assert.equal(rdd("H"), 2, "H register RDD test"); QUnit.assert.equal(rdd("S"), 3, "S register RDD test"); QUnit.assert.equal(rdd("P"), 4, "P register RDD test"); }); // Test to cover RBD function usage (lines 289-291) QUnit.test( "RBD function usage test", function() { // Direct test of RBD function var rbd = I8008.lens.RBD; QUnit.assert.equal(rbd("B"), 0, "B register RBD test"); QUnit.assert.equal(rbd("D"), 1, "D register RBD test"); QUnit.assert.equal(rbd("Z"), -1, "Invalid register RBD test"); }); // Test to cover RQQ function usage (lines 292-294) QUnit.test( "RQQ function usage test", function() { // Direct test of RQQ function var rqq = I8008.lens.RQQ; QUnit.assert.equal(rqq("B"), 0, "B register RQQ test"); QUnit.assert.equal(rqq("D"), 1, "D register RQQ test"); QUnit.assert.equal(rqq("H"), 2, "H register RQQ test"); QUnit.assert.equal(rqq("P"), 3, "P register RQQ test"); QUnit.assert.equal(rqq("S"), 4, "S register RQQ test"); QUnit.assert.equal(rqq("W"), 5, "W register RQQ test"); QUnit.assert.equal(rqq("X"), -1, "Invalid register RQQ test"); }); // Test to cover RB function (lines 295-304) QUnit.test( "RB function - LAI instruction with immediate", function() { s = {"opcode":"LAI","params":["$42"],"addr":0x100,"lens":[],"bytes":0}; p = I8008.parseOpcode(s, vars, Parser); QUnit.assert.equal(p.lens[0],0x06,"Opcode OK"); QUnit.assert.equal(typeof(p.lens[1]),"function","Function OK"); QUnit.assert.equal(p.bytes,2,"Length OK"); }); // Test to cover RR function (lines 314-318) QUnit.test( "RR function - direct register operation", function() { try { // Direct test of RR function via DCR s = {"opcode":"DCR","params":["B"],"addr":0x100,"lens":[],"bytes":0}; p = I8008.parseOpcode(s, vars, Parser); QUnit.assert.equal(p.lens[0],0x09,"Opcode OK"); QUnit.assert.equal(p.bytes,1,"Length OK"); } catch (e) { QUnit.assert.ok(false, "Should not throw error: " + e); } }); // Test to cover RR- function (lines 320-325) QUnit.test( "RR- function - exclude A register test", function() { try { // Test with valid register (not A) s = {"opcode":"INR","params":["C"],"addr":0x100,"lens":[],"bytes":0}; p = I8008.parseOpcode(s, vars, Parser); QUnit.assert.equal(p.lens[0],0x10,"Opcode OK with C register"); QUnit.assert.equal(p.bytes,1,"Length OK"); } catch (e) { QUnit.assert.ok(false, "Should not throw error: " + e); } }); // Test for RPW function complete coverage (lines 341-352) - I8008 doesn't have LXI QUnit.test( "RPW function direct test", function() { // Direct test of RPW function with mock parameters try { var rpw = I8008.lens.RPW; var result = rpw.call(I8008.lens, 0x01, ["B", "$1234"], Parser); QUnit.assert.equal(result[0], 0x01, "Opcode calculation OK"); QUnit.assert.equal(typeof(result[1]), "function", "Function parameter OK"); QUnit.assert.equal(result[2], null, "Null value OK"); QUnit.assert.equal(result.length, 3, "Array length OK"); } catch (e) { QUnit.assert.ok(false, "RPW function should not throw: " + e); } }); // Test for RPWD function complete coverage (lines 353-358) - I8008 doesn't have DAD QUnit.test( "RPWD function direct test", function() { // Direct test of RPWD function with mock parameters try { var rpwd = I8008.lens.RPWD; var result = rpwd.call(I8008.lens, 0x03, ["B"], Parser); QUnit.assert.equal(result[0], 0x03, "Opcode calculation OK"); QUnit.assert.equal(result.length, 1, "Array length OK"); } catch (e) { QUnit.assert.ok(false, "RPWD function should not throw: " + e); } }); // Test for BD function complete coverage (lines 359-364) - I8008 doesn't have LDAX QUnit.test( "BD function direct test", function() { // Direct test of BD function with mock parameters try { var bd = I8008.lens.BD; var result = bd.call(I8008.lens, 0x0a, ["B"], Parser); QUnit.assert.equal(result[0], 0x0a, "Opcode calculation OK"); QUnit.assert.equal(result.length, 1, "Array length OK"); // Test with D register var result2 = bd.call(I8008.lens, 0x0a, ["D"], Parser); QUnit.assert.equal(result2[0], 0x1a, "Opcode calculation with D register OK"); } catch (e) { QUnit.assert.ok(false, "BD function should not throw: " + e); } }); // Test for RQW function complete coverage (lines 365-369) - I8008 doesn't have PUSH QUnit.test( "RQW function direct test", function() { // Direct test of RQW function with mock parameters try { var rqw = I8008.lens.RQW; var result = rqw.call(I8008.lens, 0xc5, ["B"], Parser); QUnit.assert.equal(result[0], 0xc5, "Opcode calculation OK"); QUnit.assert.equal(result.length, 1, "Array length OK"); // Test with D register var result2 = rqw.call(I8008.lens, 0xc5, ["D"], Parser); QUnit.assert.equal(result2[0], 0xd5, "Opcode calculation with D register OK"); } catch (e) { QUnit.assert.ok(false, "RQW function should not throw: " + e); } }); // Test invalid register for RQW function error handling QUnit.test( "RQW error test - invalid register range", function() { try { var rqw = I8008.lens.RQW; var result = rqw.call(I8008.lens, 0xc5, ["Z"], Parser); } catch (e) { p = e; } QUnit.assert.equal(p,"Unknown register Z","Error detected for invalid RQW register"); }); // Test error handling for register range validation QUnit.test( "RPW error test - register out of range", function() { try { var rpw = I8008.lens.RPW; var result = rpw.call(I8008.lens, 0x01, ["X"], Parser); } catch (e) { p = e; } QUnit.assert.equal(p,"Unknown register X","Error detected for invalid RPW register"); }); // Test error handling for RPWD function QUnit.test( "RPWD error test - register out of range", function() { try { var rpwd = I8008.lens.RPWD; var result = rpwd.call(I8008.lens, 0x03, ["Y"], Parser); } catch (e) { p = e; } QUnit.assert.equal(p,"Unknown register Y","Error detected for invalid RPWD register"); }); // Test error handling for BD function QUnit.test( "BD error test - register out of range", function() { try { var bd = I8008.lens.BD; var result = bd.call(I8008.lens, 0x0a, ["C"], Parser); } catch (e) { p = e; } QUnit.assert.equal(p,"Unknown register C","Error detected for invalid BD register"); }); // Test to execute function closure in B lens function (line 310) QUnit.test( "B function closure execution test", function() { s = {"opcode":"ADI","params":["$42"],"addr":0x100,"lens":[],"bytes":0}; p = I8008.parseOpcode(s, vars, Parser); QUnit.assert.equal(p.lens[0],0x04,"Opcode OK"); QUnit.assert.equal(typeof(p.lens[1]),"function","Function OK"); QUnit.assert.equal(p.bytes,2,"Length OK"); // Execute the closure function to cover line 310 var result = p.lens[1]({}); QUnit.assert.equal(result,0x42,"Function execution result OK"); }); // Test to execute function closure in RPW lens function (line 348) QUnit.test( "RPW function closure execution test", function() { // Direct test to create RPW result and execute closure var rpw = I8008.lens.RPW; var result = rpw.call(I8008.lens, 0x01, ["B", "$5678"], Parser); QUnit.assert.equal(result[0], 0x01, "Opcode calculation OK"); QUnit.assert.equal(typeof(result[1]), "function", "Function parameter OK"); QUnit.assert.equal(result[2], null, "Null value OK"); // Execute the closure function to cover line 348 var evaluated = result[1]({}); QUnit.assert.equal(evaluated, 0x5678, "Function execution result OK"); }); // Test to execute function closure in IW lens function (line 375) QUnit.test( "IW function closure execution test", function() { s = {"opcode":"JMP","params":["$1234"],"addr":0x100,"lens":[],"bytes":0}; p = I8008.parseOpcode(s, vars, Parser); QUnit.assert.equal(p.lens[0],0x44,"Opcode OK"); QUnit.assert.equal(typeof(p.lens[1]),"function","Function OK"); QUnit.assert.equal(p.lens[2],null,"Null value OK"); QUnit.assert.equal(p.bytes,3,"Length OK"); // Execute the closure function to cover line 375 var result = p.lens[1]({}); QUnit.assert.equal(result,0x1234,"Function execution result OK"); });