├── roms
└── test
│ ├── test.com
│ ├── 8080EXER.COM
│ ├── 8080EXM.COM
│ ├── 8080PRE.COM
│ ├── CPUTEST.COM
│ └── TST8080.COM
├── SpaceInvadersJIT
├── SDL2.dll
├── ShiftRegister.cs
├── Properties
│ └── launchSettings.json
├── SpaceInvadersJIT.csproj
├── Program.cs
├── SpaceInvadersKey.cs
├── SpaceInvadersInterruptUtils.cs
└── SpaceInvadersApplication.cs
├── JIT8080
├── 8080
│ ├── Register.cs
│ ├── IRenderer.cs
│ ├── IIOHandler.cs
│ ├── IMemoryBus8080.cs
│ ├── IInterruptUtils.cs
│ └── Opcodes8080.cs
├── JIT8080.csproj
└── Generator
│ ├── Cpu8080.cs
│ ├── CpuInternalBuilders.cs
│ ├── FlagUtilities.cs
│ ├── ILGeneratorExtensions.cs
│ ├── StackUtilities.cs
│ ├── General8BitALUEmitter.cs
│ └── Emulator.cs
├── JIT8080.Tests
├── Mocks
│ ├── TestRenderer.cs
│ ├── TestIOHandler.cs
│ ├── TestInterruptUtils.cs
│ └── TestMemoryBus.cs
├── Opcodes
│ ├── LoadTests.cs
│ ├── JumpTests.cs
│ ├── ExchangeTests.cs
│ ├── RotateOperationTests.cs
│ ├── StackTests.cs
│ └── ArithmeticTests.cs
├── JIT8080.Tests.csproj
├── ValidOpcodeTests.cs
├── RegisterPairTests.cs
└── FlagRegisterTests.cs
├── CPMEmulator
├── CPMEmulator.csproj
├── Properties
│ └── launchSettings.json
├── Program.cs
└── CPMApplication.cs
├── SpaceInvadersJIT.Tests
├── MemoryBusTests.cs
├── ShiftRegisterTests.cs
└── SpaceInvadersJIT.Tests.csproj
├── LICENSE
├── azure-pipelines.yml
├── README.md
├── .gitattributes
├── SpaceInvadersJIT.sln
├── .editorconfig
├── .gitignore
└── SpaceInvadersJIT.sln.DotSettings
/roms/test/test.com:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DaveTCode/8080JIT/HEAD/roms/test/test.com
--------------------------------------------------------------------------------
/roms/test/8080EXER.COM:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DaveTCode/8080JIT/HEAD/roms/test/8080EXER.COM
--------------------------------------------------------------------------------
/roms/test/8080EXM.COM:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DaveTCode/8080JIT/HEAD/roms/test/8080EXM.COM
--------------------------------------------------------------------------------
/roms/test/8080PRE.COM:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DaveTCode/8080JIT/HEAD/roms/test/8080PRE.COM
--------------------------------------------------------------------------------
/roms/test/CPUTEST.COM:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DaveTCode/8080JIT/HEAD/roms/test/CPUTEST.COM
--------------------------------------------------------------------------------
/roms/test/TST8080.COM:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DaveTCode/8080JIT/HEAD/roms/test/TST8080.COM
--------------------------------------------------------------------------------
/SpaceInvadersJIT/SDL2.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DaveTCode/8080JIT/HEAD/SpaceInvadersJIT/SDL2.dll
--------------------------------------------------------------------------------
/JIT8080/JIT8080.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net5.0
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/JIT8080.Tests/Mocks/TestRenderer.cs:
--------------------------------------------------------------------------------
1 | using JIT8080._8080;
2 |
3 | namespace JIT8080.Tests.Mocks
4 | {
5 | public class TestRenderer : IRenderer
6 | {
7 | public void VBlank()
8 | {
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/SpaceInvadersJIT/ShiftRegister.cs:
--------------------------------------------------------------------------------
1 | namespace SpaceInvadersJIT
2 | {
3 | internal struct ShiftRegister
4 | {
5 | internal ushort Register;
6 | internal byte Offset;
7 |
8 | internal byte Value() => (byte) (Register >> (8 - Offset));
9 | }
10 | }
--------------------------------------------------------------------------------
/SpaceInvadersJIT/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "SpaceInvadersJIT": {
4 | "commandName": "Project"
5 | },
6 | "Space Invaders (Rom)": {
7 | "commandName": "Project",
8 | "commandLineArgs": "..\\..\\..\\..\\roms\\real\\invaders.rom"
9 | }
10 | }
11 | }
--------------------------------------------------------------------------------
/CPMEmulator/CPMEmulator.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net5.0
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/JIT8080/8080/Register.cs:
--------------------------------------------------------------------------------
1 | namespace JIT8080._8080
2 | {
3 | internal enum Register
4 | {
5 | A = 0b111,
6 | B = 0b000,
7 | C = 0b001,
8 | D = 0b010,
9 | E = 0b011,
10 | H = 0b100,
11 | L = 0b101,
12 | M = 0b110 // Memory address referred to by contents of HL
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/JIT8080.Tests/Mocks/TestIOHandler.cs:
--------------------------------------------------------------------------------
1 | using JIT8080._8080;
2 |
3 | namespace JIT8080.Tests.Mocks
4 | {
5 | internal class TestIOHandler : IIOHandler
6 | {
7 | public void Out(byte port, byte value)
8 | {
9 |
10 | }
11 |
12 | public byte In(byte port)
13 | {
14 | return 0x0;
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/JIT8080/8080/IRenderer.cs:
--------------------------------------------------------------------------------
1 | namespace JIT8080._8080
2 | {
3 | ///
4 | /// This interface is passed to the CPU emulator and is fired on each
5 | /// VBlank interrupt allowing the calling code to perform draw (or other)
6 | /// functions whilst the CPU is halted
7 | ///
8 | public interface IRenderer
9 | {
10 | public void VBlank();
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/JIT8080.Tests/Mocks/TestInterruptUtils.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection.Emit;
2 | using JIT8080._8080;
3 | using JIT8080.Generator;
4 |
5 | namespace JIT8080.Tests.Mocks
6 | {
7 | public class TestInterruptUtils : IInterruptUtils
8 | {
9 | public void PreProgramEmit(ILGenerator methodIL)
10 | {
11 | }
12 |
13 | public void PostInstructionEmit(ILGenerator methodIL, CpuInternalBuilders internals, ushort programCounter)
14 | {
15 |
16 | }
17 | }
18 | }
--------------------------------------------------------------------------------
/JIT8080/8080/IIOHandler.cs:
--------------------------------------------------------------------------------
1 | namespace JIT8080._8080
2 | {
3 | ///
4 | /// The 8080 uses two instructions (OUT d8 & IN d8) to talk directly to up
5 | /// to 255 connected ports.
6 | ///
7 | /// This class allows definition of those ports in managed code where the
8 | /// dynamically generated CLR IL can call the In/Out functions directly.
9 | ///
10 | public interface IIOHandler
11 | {
12 | public void Out(byte port, byte value);
13 |
14 | public byte In(byte port);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/CPMEmulator/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "General": {
4 | "commandName": "Project"
5 | },
6 | "8080PRE.COM": {
7 | "commandName": "Project",
8 | "commandLineArgs": "..\\..\\..\\..\\roms\\test\\8080PRE.COM"
9 | },
10 | "TST8080.COM": {
11 | "commandName": "Project",
12 | "commandLineArgs": "..\\..\\..\\..\\roms\\test\\TST8080.COM"
13 | },
14 | "test.com": {
15 | "commandName": "Project",
16 | "commandLineArgs": "..\\..\\..\\..\\roms\\test\\test.com"
17 | }
18 | }
19 | }
--------------------------------------------------------------------------------
/JIT8080.Tests/Mocks/TestMemoryBus.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using JIT8080._8080;
3 |
4 | namespace JIT8080.Tests.Mocks
5 | {
6 | internal class TestMemoryBus : IMemoryBus8080
7 | {
8 | private readonly byte[] _memory = new byte[0x10000];
9 |
10 | internal TestMemoryBus(byte[] rom)
11 | {
12 | Array.Copy(rom, _memory, Math.Min(_memory.Length, rom.Length));
13 | }
14 |
15 | public byte ReadByte(ushort address) => _memory[address];
16 |
17 | public void WriteByte(byte value, ushort address)
18 | {
19 | _memory[address] = value;
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/SpaceInvadersJIT/SpaceInvadersJIT.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net5.0
6 |
7 |
8 |
9 | true
10 |
11 |
12 |
13 | true
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | PreserveNewest
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/JIT8080/8080/IMemoryBus8080.cs:
--------------------------------------------------------------------------------
1 | namespace JIT8080._8080
2 | {
3 | ///
4 | /// Provides an interface for the CPU to access whatever is connected to
5 | /// it's address bus
6 | ///
7 | ///
8 | /// Due to the simplicity of space invaders (no MMIO like GB, NES etc) this
9 | /// _could_ really just be a bare array in the generated IL and access to
10 | /// it would not require the function call.
11 | ///
12 | /// However, this architecture better demonstrates the emulation technique
13 | /// and would allow for it to be used in MMIO based architectures.
14 | ///
15 | public interface IMemoryBus8080
16 | {
17 | public byte ReadByte(ushort address);
18 |
19 | public void WriteByte(byte value, ushort address);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/SpaceInvadersJIT.Tests/MemoryBusTests.cs:
--------------------------------------------------------------------------------
1 | using Xunit;
2 |
3 | namespace SpaceInvadersJIT.Tests
4 | {
5 | public class MemoryBusTests
6 | {
7 | [Fact]
8 | public void TestMemoryBusReadWrite()
9 | {
10 | var program = new byte[0x2000];
11 | var memoryBus = new SpaceInvadersApplication(program);
12 |
13 | for (ushort ii = 0; ii < ushort.MaxValue; ii++)
14 | {
15 | memoryBus.WriteByte((byte)(ii + 1), ii);
16 | if (ii < 0x2000)
17 | {
18 | Assert.Equal(0, memoryBus.ReadByte(ii));
19 | }
20 | else
21 | {
22 | Assert.Equal((byte)(ii + 1), memoryBus.ReadByte(ii));
23 | }
24 | }
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/CPMEmulator/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using JIT8080.Generator;
4 |
5 | namespace CPMEmulator
6 | {
7 | internal static class Program
8 | {
9 | private static void Main(string[] args)
10 | {
11 | var rom = args.Length switch
12 | {
13 | > 0 => File.ReadAllBytes(args[0]),
14 | _ => new byte[] { 0x04, 0x00, 0x00, 0x76 }
15 | };
16 | var application = new CPMApplication(rom);
17 | application.Emulator = Emulator.CreateEmulator(application.CompleteProgram(), application, application, application, application, 0x100);
18 | var runDelegate = (Action) application.Emulator.Run.CreateDelegate(typeof(Action), application.Emulator.Emulator);
19 |
20 | runDelegate();
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/JIT8080/8080/IInterruptUtils.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Reflection.Emit;
3 | using JIT8080.Generator;
4 |
5 | namespace JIT8080._8080
6 | {
7 | ///
8 | /// Interrupts are handled in different ways on different systems,
9 | /// to support firing interrupts at the right moment this interface can
10 | /// be overridden to inject appropriate IL stream commands.
11 | ///
12 | public interface IInterruptUtils
13 | {
14 | ///
15 | /// This is typically used to declare locals and set their values and
16 | /// occurs at the start of the method
17 | ///
18 | public void PreProgramEmit(ILGenerator methodIL);
19 |
20 | ///
21 | /// This is called after each instruction executes and is used to
22 | /// check whether an interrupt should be fired.
23 | ///
24 | public void PostInstructionEmit(ILGenerator methodIL, CpuInternalBuilders internals, ushort programCounter);
25 | }
26 | }
--------------------------------------------------------------------------------
/JIT8080.Tests/Opcodes/LoadTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using JIT8080.Generator;
3 | using JIT8080.Tests.Mocks;
4 | using Xunit;
5 |
6 | namespace JIT8080.Tests.Opcodes
7 | {
8 | ///
9 | /// Test simple instructions to read/write registers to memory
10 | ///
11 | public class LoadTests
12 | {
13 | [Fact]
14 | public void TestLDAAndSTA()
15 | {
16 | var rom = new byte[] {0x32, 0x00, 0x01, 0xAF, 0x3A, 0x00, 0x01, 0x76};
17 | var memoryBus = new TestMemoryBus(rom);
18 | var emulator =
19 | Emulator.CreateEmulator(rom, memoryBus, new TestIOHandler(), new TestRenderer(), new TestInterruptUtils());
20 | emulator.Internals.A.SetValue(emulator.Emulator, (byte)0x10);
21 |
22 | emulator.Run.Invoke(emulator.Emulator, Array.Empty