public void CartridgeNameExceptsAStringLiteral(string invalidCartridgeName) { const string inputTemplate = @" header {{ CartridgeName = {0} }} vectors {{ }} procedure Main {{ sei clc xce }} "; string input = String.Format(inputTemplate, invalidCartridgeName); ZealCpuDriver driver = new ZealCpuDriver(input.ToMemoryStream()); Assert.Throws<CompilerErrorException>(() => driver.Parse()); }
public void ShouldGenerateAbsoluteInstructionsWithLabel() { string input = @"procedure Test { php mainLoop: jmp mainLoop } "; ZealCpuDriver driver = new ZealCpuDriver(input.ToMemoryStream()); driver.Parse(); RomHeader fakeHeader = new RomHeader(); fakeHeader.MapMode = MapMode.LoROM; fakeHeader.RomSpeed = RomSpeed.SlowROM; MemoryStream memoryStream = new MemoryStream(32); CpuCodeGenerator generator = new CpuCodeGenerator(memoryStream); generator.Instructions = driver.GlobalScope.Children[0].Statements.Where(x => x is CpuInstructionStatement).Select(x => x as CpuInstructionStatement).ToList(); generator.Scope = driver.GlobalScope.Children[0]; generator.Header = fakeHeader; generator.Generate(); Assert.Equal(0x01, memoryStream.GetBuffer()[2]); Assert.Equal(0x80, memoryStream.GetBuffer()[3]); }
public void CheckInvalidAddressingMode(string instruction) { const string inputTemplate = @" vectors {{ BRK = EmptyVector NMI = EmptyVector IRQ = EmptyVector Reset = Main }} procedure Main {{ {0} }} interrupt EmptyVector {{ }} "; string input = String.Format(inputTemplate, instruction); ZealCpuDriver driver = new ZealCpuDriver(input.ToMemoryStream()); Assert.Throws<CompilerErrorException>(() => driver.Parse()); }
public void ShoulResolveLabelsToAddress() { string input = @"procedure Test { php pha mainLoop: lda $2007 jmp mainLoop bra exit exit: rts } interrupt EmptyVector { } "; ZealCpuDriver driver = new ZealCpuDriver(input.ToMemoryStream()); driver.Parse(); Assert.Equal(0, driver.GlobalScope.AddressFor("Test")); Assert.Equal(11, driver.GlobalScope.AddressFor("EmptyVector")); var testScope = driver.GlobalScope.Children[0]; Assert.Equal(2, testScope.AddressFor("mainLoop")); Assert.Equal(10, testScope.AddressFor("exit")); }
public void ShouldMarkRelativeLabelArgument(string instructionText) { string input = String.Format(ProcedureTemplate, instructionText); ZealCpuDriver driver = new ZealCpuDriver(input.ToMemoryStream()); driver.Parse(); var instruction = driver.GlobalScope.Children[0].Statements[0] as CpuInstructionStatement; Assert.Equal(CpuAddressingMode.Relative, instruction.AddressingMode); }
public void ShouldResolveLabelsOutsideScope() { const string input = @" vectors { BRK = EmptyVector IRQ = EmptyVector NMI = EmptyVector Reset = Main } procedure Main { jsr Test } procedure Test { php rep #$30 pha lda #$03 pla plp rts } interrupt EmptyVector { } "; ZealCpuDriver driver = new ZealCpuDriver(input.ToMemoryStream()); driver.Parse(); driver.SecondPass(); var mainProcedure = driver.GlobalScope.Children[0]; Assert.Equal(true, mainProcedure.IsLabelValid("Test")); Assert.Equal(3, mainProcedure.AddressFor("Test")); }
public void ShouldAddRTIWhenParsingInterrupt() { const string input = @"interrupt NMI { php pha pla plp }"; ZealCpuDriver driver = new ZealCpuDriver(input.ToMemoryStream()); driver.Parse(); var cpuInstruction = driver.GlobalScope.Children[0].Statements[driver.GlobalScope.Children[0].Statements.Count - 1] as CpuInstructionStatement; Assert.Equal("NMI", driver.GlobalScope.Children[0].Name); Assert.Equal(ScopeType.Interrupt, driver.GlobalScope.Children[0].Type); Assert.Equal(CpuInstructions.rti, cpuInstruction.Opcode); Assert.Equal(CpuAddressingMode.Implied, cpuInstruction.AddressingMode); }
public void ShouldFailOnInvalidVectorsLabel() { const string input = @" vectors { BRK = EmptyVector NMI = EmptyVector IRQ = EmptyVector Reset = NotValidReset } procedure Main { sei clc xce } interrupt EmptyVector { } "; ZealCpuDriver driver = new ZealCpuDriver(input.ToMemoryStream()); driver.Parse(); Assert.Throws<CompilerErrorException>(() => driver.SecondPass()); }
public void ShouldFailOnInvalidVectorsEntryName() { const string input = @" vectors { NormalNMI = Main } procedure Main { sei clc xce } " ; ZealCpuDriver driver = new ZealCpuDriver(input.ToMemoryStream()); Assert.Throws<CompilerErrorException>(() => driver.Parse()); }
public void ShouldFailOnInvalidHeaderEntryName() { const string input = @" header { CartName = ""HELLO WORLD"" } vectors { } procedure Main { sei clc xce } "; ZealCpuDriver driver = new ZealCpuDriver(input.ToMemoryStream()); Assert.Throws<CompilerErrorException>(() => driver.Parse()); }
public void ShouldFailOnBranchTooLong() { const string input = @" vectors { BRK = EmptyVector NMI = EmptyVector IRQ = EmptyVector Reset = Main } procedure Main { bra forwardLabel backwardLabel: sta $7E0000 sta $7E0000 sta $7E0000 sta $7E0000 sta $7E0000 sta $7E0000 sta $7E0000 sta $7E0000 sta $7E0000 sta $7E0000 sta $7E0000 sta $7E0000 sta $7E0000 sta $7E0000 sta $7E0000 sta $7E0000 sta $7E0000 sta $7E0000 sta $7E0000 sta $7E0000 sta $7E0000 sta $7E0000 sta $7E0000 sta $7E0000 sta $7E0000 sta $7E0000 sta $7E0000 sta $7E0000 sta $7E0000 sta $7E0000 sta $7E0000 sta $7E0000 sta $7E0000 sta $7E0000 sta $7E0000 sta $7E0000 sta $7E0000 sta $7E0000 sta $7E0000 forwardLabel: bra backwardLabel } interrupt EmptyVector { } "; ZealCpuDriver driver = new ZealCpuDriver(input.ToMemoryStream()); Assert.Throws<CompilerErrorException>(() => driver.Parse()); Assert.Equal(2, driver.Errors.Count); }
public void ShouldParseArgumentSizeCorrectly(string instruction, int value, ArgumentSize size) { string input = String.Format(ProcedureTemplate, instruction); ZealCpuDriver driver = new ZealCpuDriver(input.ToMemoryStream()); driver.Parse(); CpuInstructionStatement instructionStatement = driver.GlobalScope.Children[0].Statements[0] as CpuInstructionStatement; var argument = instructionStatement.Arguments[0] as NumberInstructionArgument; Assert.Equal(value, argument.Number); Assert.Equal(size, argument.Size); }
public void ShouldParseInterrupt() { const string input = @"interrupt EmptyVector { }"; ZealCpuDriver driver = new ZealCpuDriver(input.ToMemoryStream()); driver.Parse(); Assert.Equal("EmptyVector", driver.GlobalScope.Children[0].Name); Assert.Equal(ScopeType.Interrupt, driver.GlobalScope.Children[0].Type); }
static int Main(string[] args) { if (args.Length < 1) { Console.Error.WriteLine("No source file provided."); return 1; } if (Path.GetExtension(args[0]) != ".zcpu") { Console.Error.WriteLine("The source file is in the wrong format. The source file must ends with .zcpu."); return 1; } ZealCpuDriver driver = new ZealCpuDriver(args[0]); try { driver.Parse(); driver.SecondPass(); } catch(CompilerErrorException) { foreach (var error in driver.Errors) { printErrorMessage(error); } #if DEBUG Console.Read(); #endif return 1; } FileStream outputRom = new FileStream(Path.ChangeExtension(args[0], ".sfc"), FileMode.Create); CpuCodeGenerator codeGenerator = new CpuCodeGenerator(outputRom); codeGenerator.Header = driver.Header; foreach (var scope in driver.GlobalScope.Children) { codeGenerator.Scope = scope; List<CpuInstructionStatement> instructions = new List<CpuInstructionStatement>(); foreach (var statement in scope.Statements) { if (statement is CpuInstructionStatement) { instructions.Add((CpuInstructionStatement)statement); } } codeGenerator.Instructions = instructions; codeGenerator.Generate(); } SfcRomWriter romWriter = new SfcRomWriter(outputRom); romWriter.Driver = driver; romWriter.Write(); outputRom.Close(); using (FileStream newRom = new FileStream(Path.ChangeExtension(args[0], ".sfc"), FileMode.Open)) { SfcRomWriter checksumWriter = new SfcRomWriter(newRom); checksumWriter.Driver = driver; checksumWriter.ComputeChecksum(); } return 0; }
public void ShouldParseVectorsInfo() { const string input = @" vectors { BRK = BrkVector IRQ = IrqVector NMI = NmiVector Reset = Main } "; ZealCpuDriver driver = new ZealCpuDriver(input.ToMemoryStream()); driver.Parse(); Assert.Equal("BrkVector", driver.Vectors.BRK); Assert.Equal("IrqVector", driver.Vectors.IRQ); Assert.Equal("NmiVector", driver.Vectors.NMI); Assert.Equal("Main", driver.Vectors.Reset); }
public void ShouldParseProcedure() { const string input = @"procedure Test { }"; ZealCpuDriver driver = new ZealCpuDriver(input.ToMemoryStream()); driver.Parse(); Assert.Equal("Test", driver.GlobalScope.Children[0].Name); Assert.Equal(ScopeType.Procedure, driver.GlobalScope.Children[0].Type); }
public void ShouldParseLabelArgument() { string input = @"procedure Test { jmp mainLoop }"; ZealCpuDriver driver = new ZealCpuDriver(input.ToMemoryStream()); driver.Parse(); var instruction = driver.GlobalScope.Children[0].Statements[0] as CpuInstructionStatement; var argument = instruction.Arguments[0] as LabelInstructionArgument; Assert.Equal("mainLoop", argument.Label); }
public void ShouldParseLabel() { const string input = @"procedure Test { php pha mainLoop: lda $2007 jmp mainLoop exit: rts }"; ZealCpuDriver driver = new ZealCpuDriver(input.ToMemoryStream()); driver.Parse(); var thirdInstruction = driver.GlobalScope.Children[0].Statements[2]; var fiveInstruction = driver.GlobalScope.Children[0].Statements[4]; Assert.Equal("mainLoop", thirdInstruction.AssociatedLabel); Assert.Equal("exit", fiveInstruction.AssociatedLabel); }
public void VectorsIsRequired() { const string input = @" header { CartridgeName = ""HELLO WORLD SNES"" RomSpeed = SlowROM MapMode = LoROM SramSize = 0 Country = Japan Developer = 0 Version = 0 } procedure Main { sei clc xce } " ; ZealCpuDriver driver = new ZealCpuDriver(input.ToMemoryStream()); driver.Parse(); Assert.Throws<CompilerErrorException>(() => driver.SecondPass()); Assert.Equal(1, driver.Errors.Count); }
public void ShouldParseHeaderInfo() { const string input = @" header { CartridgeName = ""HELLO WORLD SNES"" RomSpeed = FastROM MapMode = HiROM SramSize = 32 Country = NorthAmerica Developer = $1A Version = %1010 } "; ZealCpuDriver driver = new ZealCpuDriver(input.ToMemoryStream()); driver.Parse(); Assert.Equal("HELLO WORLD SNES", driver.Header.CartridgeName); Assert.Equal(RomSpeed.FastROM, driver.Header.RomSpeed); Assert.Equal(MapMode.HiROM, driver.Header.MapMode); Assert.Equal(32u, driver.Header.SramSize); Assert.Equal(Country.NorthAmerica, driver.Header.Country); Assert.Equal(0x1Au, driver.Header.Developer); Assert.Equal(10u, driver.Header.Version); }
public void VectorsShouldBeFullyPopulated() { const string input = @" vectors { Reset = Main } procedure Main { sei clc xce } " ; ZealCpuDriver driver = new ZealCpuDriver(input.ToMemoryStream()); Assert.Throws<CompilerErrorException>(() => driver.Parse()); }
public void InstructionsShouldHaveArguments() { const string input = @" vectors { BRK = EmptyVector NMI = EmptyVector IRQ = EmptyVector Reset = Main } procedure Main { lda } interrupt EmptyVector { } "; ZealCpuDriver driver = new ZealCpuDriver(input.ToMemoryStream()); Assert.Throws<CompilerErrorException>(() => driver.Parse()); }
public void CountryShouldBeValid(string country) { const string inputTemplate = @" header {{ Country = {0} }} vectors {{ }} procedure Main {{ sei clc xce }} "; string input = String.Format(inputTemplate, country); ZealCpuDriver driver = new ZealCpuDriver(input.ToMemoryStream()); Assert.Throws<CompilerErrorException>(() => driver.Parse()); }
public void ShouldParseImpliedInstructions(string opcodeText, CpuInstructions opcodeEnum) { string input = String.Format(ProcedureTemplate, opcodeText); ZealCpuDriver driver = new ZealCpuDriver(input.ToMemoryStream()); driver.Parse(); CpuInstructionStatement instructionStatement = driver.GlobalScope.Children[0].Statements[0] as CpuInstructionStatement; Assert.Equal(opcodeEnum, instructionStatement.Opcode); Assert.Equal(CpuAddressingMode.Implied, instructionStatement.AddressingMode); }
public void ShouldParseAbsoluteInstructions(string instruction, CpuInstructions opcodeEnum, int value) { string input = String.Format(ProcedureTemplate, instruction); ZealCpuDriver driver = new ZealCpuDriver(input.ToMemoryStream()); driver.Parse(); CpuInstructionStatement instructionStatement = driver.GlobalScope.Children[0].Statements[0] as CpuInstructionStatement; Assert.Equal(opcodeEnum, instructionStatement.Opcode); Assert.Equal(CpuAddressingMode.Absolute, instructionStatement.AddressingMode); var numberArgument = instructionStatement.Arguments[0] as NumberInstructionArgument; Assert.Equal(value, numberArgument.Number); }
public void ShouldGenerateRelativeInstructionsWithLabel() { string input = @"procedure Test { php backwardBranch: sec bvs backwardBranch lda #$03 bra forwardBranch tax tay forwardBranch: rts } "; ZealCpuDriver driver = new ZealCpuDriver(input.ToMemoryStream()); driver.Parse(); MemoryStream memoryStream = new MemoryStream(32); CpuCodeGenerator generator = new CpuCodeGenerator(memoryStream); generator.Instructions = driver.GlobalScope.Children[0].Statements.Where(x => x is CpuInstructionStatement).Select(x => x as CpuInstructionStatement).ToList(); generator.Scope = driver.GlobalScope.Children[0]; generator.Generate(); Assert.Equal(0xFD, memoryStream.GetBuffer()[3]); Assert.Equal(0x02, memoryStream.GetBuffer()[7]); }