Esempio n. 1
0
        public void Adding_MemorySegmentBank_With_SegmentNumber_That_Does_Not_Exists_Is_Not_Allowed_And_Throws_Exception()
        {
            // Arrange
            var mem = new Memory(enableBankSwitching: true);

            // Act/Assert
            Assert.Throws <ArgumentException>(() => mem.AddMemorySegmentBank(segmentNumber: (byte)mem.MemorySegments.Count, new byte[Memory.ADDITIONAL_SEGMENT_SIZE]));
        }
Esempio n. 2
0
        public void Adding_MemorySegmentBank_With_Size_Not_Same_As_Segment_Size_Is_Not_Allowed_And_Throws_Exception()
        {
            // Arrange
            var mem = new Memory(enableBankSwitching: true);

            // Act/Assert
            Assert.Throws <ArgumentException>(() => mem.AddMemorySegmentBank(segmentNumber: 1, new byte[1234]));
        }
Esempio n. 3
0
        public void Can_Change_Segment_Memory_Bank_By_Setting_Special_Memory_Location()
        {
            // Arrange
            var mem = new Memory(enableBankSwitching: true);

            // Add a new bank to segment 1 with blank RAM. Segment 1 starts at 8192 (0x2000).
            // Adding a new bank does not change current bank number (which will still be 0)
            mem.AddMemorySegmentBank(1);

            // Fill some data in to segment 1 in current bank number (0).
            mem[0x2000] = 0x42;
            mem[0x2001] = 0x21;

            // Load machine code into memory that will switch segment 1 bank from 0 to 1
            ushort codeAddress    = 0xc000;
            ushort codeInsAddress = codeAddress;

            // Prepare memory address 0x02 with memory segment bank number to use. Writing to 0x02 will not actually do the change.
            mem[codeInsAddress++] = (byte)OpCodeId.LDA_I;   // LDA (Load Accumulator)
            mem[codeInsAddress++] = 0x01;                   //  |-Value: The memory segment bank number to put in actual memory
            mem[codeInsAddress++] = (byte)OpCodeId.STA_ZP;  // STA (Store Accumulator)
            mem[codeInsAddress++] = 0x02;                   //  |-ZeroPage address $0002
            // Write the segment number to address 0x01, which will trigger the bank number specified in 0x01 to be loaded in to the segment number written to 0x01.
            mem[codeInsAddress++] = (byte)OpCodeId.LDA_I;   // LDA (Load Accumulator)
            mem[codeInsAddress++] = 0x01;                   //  |-Value: The memory segment number to change.
            mem[codeInsAddress++] = (byte)OpCodeId.STA_ZP;  // STA (Store Accumulator)
            mem[codeInsAddress++] = 0x01;                   //  |-ZeroPage address $0001
            mem[codeInsAddress++] = 0x00;                   // BRK (Break/Force Interrupt) - emulator configured to stop execution when reaching this instruction

            // Initialize emulator with CPU, memory, and execution parameters
            var computerBuilder = new ComputerBuilder();

            computerBuilder
            .WithCPU()
            .WithStartAddress(codeAddress)
            .WithMemory(mem)
            .WithInstructionExecutedEventHandler(
                (s, e) => Debug.WriteLine(OutputGen.GetLastInstructionDisassembly(e.CPU, e.Mem)))
            .WithExecOptions(options =>
            {
                options.ExecuteUntilInstruction = OpCodeId.BRK;     // Emulator will stop executing when a BRK instruction is reached.
            });
            var computer = computerBuilder.Build();

            // Act
            computer.Run();

            // Assert
            // Check that segment 1 now has changed bank number to 1.
            Assert.Equal(1, mem.MemorySegments[1].CurrentBankNumber);
            // Check that content of the memory in segment 1 now is blank (bank 1 was blank when we added it)
            Assert.Equal(0x00, mem[0x2000]);
            Assert.Equal(0x00, mem[0x2001]);
        }
Esempio n. 4
0
        private Computer SetupEmulator(EmulatorConfig emulatorConfig)
        {
            Debug.WriteLine($"Loading 6502 machine code binary file.");
            Debug.WriteLine($"{emulatorConfig.ProgramBinaryFile}");
            if (!File.Exists(emulatorConfig.ProgramBinaryFile))
            {
                Debug.WriteLine($"File does not exist.");
                throw new Exception($"Cannot find 6502 binary file: {emulatorConfig.ProgramBinaryFile}");
            }

            var enableBankSwitching = emulatorConfig.Memory.MemoryBanks.EnableMemoryBanks;
            var mem = new Memory(enableBankSwitching: enableBankSwitching);

            if (enableBankSwitching)
            {
                // Add additional memory banks for memory segment 1 (0x2000) and up (segment 0 cannot have multiple banks)
                for (byte memorySegmentNumber = 1; memorySegmentNumber < mem.MemorySegments.Count; memorySegmentNumber++)
                {
                    // By default each segment has one bank when Memory is created above.
                    // Thus we add the specified BanksPerSegment-1 new banks to each segment.
                    for (int i = 0; i < emulatorConfig.Memory.MemoryBanks.BanksPerSegment - 1; i++)
                    {
                        // Add additional memory banks for segment. Memory in those will be blank (0x00).
                        mem.AddMemorySegmentBank(memorySegmentNumber);
                    }
                }
            }

            BinaryLoader.Load(
                mem,
                emulatorConfig.ProgramBinaryFile,
                out ushort loadedAtAddress,
                out int fileLength);

            // Initialize emulator with CPU, memory, and execution parameters
            var computerBuilder = new ComputerBuilder();

            computerBuilder
            .WithCPU()
            .WithStartAddress(loadedAtAddress)
            .WithMemory(mem)
            .WithExecOptions(options =>
            {
                // Emulator will stop executing when a BRK instruction is reached.
                options.ExecuteUntilInstruction = emulatorConfig.StopAtBRK?OpCodeId.BRK:null;
            });

            var computer = computerBuilder.Build();

            return(computer);
        }
Esempio n. 5
0
        public void Can_Switch_SegmentBank()
        {
            // Arrange
            var mem = new Memory(enableBankSwitching: true);

            mem.AddMemorySegmentBank(segmentNumber: 1, new byte[Memory.ADDITIONAL_SEGMENT_SIZE]);

            mem[0x2000] = 0x42;
            mem[0x2001] = 0x21;

            // Act
            mem.ChangeCurrentSegmentBank(segmentNumber: 1, segmentBankNumber: 1);

            // Assert
            var data = mem.ReadData(0x2000, 2);

            Assert.Equal(0x00, data[0]);
            Assert.Equal(0x00, data[1]);
        }
Esempio n. 6
0
        public void Can_Switching_SegmentBank_In_One_Segment_Does_Not_Affect_Other_Segments()
        {
            // Arrange
            var mem = new Memory(enableBankSwitching: true);

            mem.AddMemorySegmentBank(segmentNumber: 1, new byte[Memory.ADDITIONAL_SEGMENT_SIZE]);

            mem[0x2000] = 0x42;
            mem[0x2001] = 0x21;

            // This memory (in segment number 2) should not be effected by changing bank in segment 1
            mem[0x4000] = 0x20;
            mem[0x4001] = 0x40;

            // Act
            mem.ChangeCurrentSegmentBank(segmentNumber: 1, segmentBankNumber: 1);

            // Assert
            var data = mem.ReadData(0x4000, 2);

            Assert.Equal(0x20, data[0]);
            Assert.Equal(0x40, data[1]);
        }