Compare commits
	
		
			No commits in common. "c18615c6298273de1548fbc20a15b8837e12efdf" and "1bae615b39481ebba1bab4bae348074251988229" have entirely different histories.
		
	
	
		
			c18615c629
			...
			1bae615b39
		
	
		
							
								
								
									
										42
									
								
								gb/bus.go
									
									
									
									
									
								
							
							
						
						
									
										42
									
								
								gb/bus.go
									
									
									
									
									
								
							@ -4,27 +4,12 @@ import (
 | 
				
			|||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// 0x0000 - 0x3FFF : ROM Bank 0
 | 
					 | 
				
			||||||
// 0x4000 - 0x7FFF : ROM Bank 1 - Switchable
 | 
					 | 
				
			||||||
// 0x8000 - 0x97FF : CHR RAM
 | 
					 | 
				
			||||||
// 0x9800 - 0x9BFF : BG Map 1
 | 
					 | 
				
			||||||
// 0x9C00 - 0x9FFF : BG Map 2
 | 
					 | 
				
			||||||
// 0xA000 - 0xBFFF : Cartridge RAM
 | 
					 | 
				
			||||||
// 0xC000 - 0xCFFF : RAM Bank 0
 | 
					 | 
				
			||||||
// 0xD000 - 0xDFFF : RAM Bank 1-7 - switchable - Color only
 | 
					 | 
				
			||||||
// 0xE000 - 0xFDFF : Reserved - Echo RAM
 | 
					 | 
				
			||||||
// 0xFE00 - 0xFE9F : Object Attribute Memory
 | 
					 | 
				
			||||||
// 0xFEA0 - 0xFEFF : Reserved - Unusable
 | 
					 | 
				
			||||||
// 0xFF00 - 0xFF7F : I/O Registers
 | 
					 | 
				
			||||||
// 0xFF80 - 0xFFFE : Zero Page
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type Bus struct {
 | 
					type Bus struct {
 | 
				
			||||||
	Cart *Cartridge
 | 
						Cart *Cartridge
 | 
				
			||||||
	RAM  *RAM
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewBus(cart *Cartridge) *Bus {
 | 
					func NewBus(cart *Cartridge) *Bus {
 | 
				
			||||||
	bus := Bus{Cart: cart, RAM: NewRAM()}
 | 
						bus := Bus{Cart: cart}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return &bus
 | 
						return &bus
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -38,21 +23,12 @@ func (bus *Bus) Read(address uint16) byte {
 | 
				
			|||||||
			return 0
 | 
								return 0
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return value
 | 
							return value
 | 
				
			||||||
	} else if address < 0xE000 {
 | 
					 | 
				
			||||||
		return bus.RAM.WRAMRead(address)
 | 
					 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		fmt.Printf("Reading from bus address %X not implemented!\n", address)
 | 
							fmt.Printf("Reading from bus address %X not implemented!\n", address)
 | 
				
			||||||
		return 0
 | 
							return 0
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (bus *Bus) Read16(address uint16) uint16 {
 | 
					 | 
				
			||||||
	lo := bus.Read(address)
 | 
					 | 
				
			||||||
	hi := bus.Read(address + 1)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return uint16(lo) | uint16(hi)<<8
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (bus *Bus) Write(address uint16, value byte) error {
 | 
					func (bus *Bus) Write(address uint16, value byte) error {
 | 
				
			||||||
	if address < 0x8000 {
 | 
						if address < 0x8000 {
 | 
				
			||||||
		// ROM data
 | 
							// ROM data
 | 
				
			||||||
@ -61,23 +37,7 @@ func (bus *Bus) Write(address uint16, value byte) error {
 | 
				
			|||||||
			return fmt.Errorf("Error writing to bus address %X: %s", address, err)
 | 
								return fmt.Errorf("Error writing to bus address %X: %s", address, err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return nil
 | 
							return nil
 | 
				
			||||||
	} else if address < 0xE000 {
 | 
					 | 
				
			||||||
		bus.RAM.WRAMWrite(address, value)
 | 
					 | 
				
			||||||
		return nil
 | 
					 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		return fmt.Errorf("Writing to bus address %X not implemented!", address)
 | 
							return fmt.Errorf("Writing to bus address %X not implemented!", address)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
func (bus *Bus) Write16(address uint16, value uint16) error {
 | 
					 | 
				
			||||||
	err := bus.Write(address+1, byte((value>>8)&0xFF))
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	err = bus.Write(address, byte(value&0xFF))
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										93
									
								
								gb/cpu.go
									
									
									
									
									
								
							
							
						
						
									
										93
									
								
								gb/cpu.go
									
									
									
									
									
								
							@ -30,20 +30,16 @@ type Registers struct {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type CPU struct {
 | 
					type CPU struct {
 | 
				
			||||||
	Bus                   *Bus
 | 
						Bus      *Bus
 | 
				
			||||||
	Regs                  Registers
 | 
						Regs     Registers
 | 
				
			||||||
	Halted                bool
 | 
						Halted   bool
 | 
				
			||||||
	Stepping              bool
 | 
						Stepping bool
 | 
				
			||||||
	InterruptMasterEnable bool
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewCPU(bus *Bus) *CPU {
 | 
					func NewCPU(bus *Bus) *CPU {
 | 
				
			||||||
	cpu := CPU{}
 | 
						cpu := CPU{}
 | 
				
			||||||
	cpu.Bus = bus
 | 
						cpu.Bus = bus
 | 
				
			||||||
	// NOTE(m): PC is usually set to 0x100 by the boot rom
 | 
						cpu.Regs = Registers{}
 | 
				
			||||||
	// TODO(m): SP is usually set programmatically by the cartridge code.
 | 
					 | 
				
			||||||
	// Remove this hardcoded value later!
 | 
					 | 
				
			||||||
	cpu.Regs = Registers{PC: 0x100, SP: 0xDFFF}
 | 
					 | 
				
			||||||
	cpu.Stepping = true
 | 
						cpu.Stepping = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return &cpu
 | 
						return &cpu
 | 
				
			||||||
@ -52,34 +48,15 @@ func NewCPU(bus *Bus) *CPU {
 | 
				
			|||||||
func (cpu *CPU) Step() {
 | 
					func (cpu *CPU) Step() {
 | 
				
			||||||
	if !cpu.Halted {
 | 
						if !cpu.Halted {
 | 
				
			||||||
		opcode := cpu.Bus.Read(cpu.Regs.PC)
 | 
							opcode := cpu.Bus.Read(cpu.Regs.PC)
 | 
				
			||||||
 | 
							cpu.Regs.PC++
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		fmt.Printf("%04X: (%02X %02X %02X) A: %02X B: %02X C: %02X\n", cpu.Regs.PC,
 | 
							fmt.Printf("%04X: (%02X %02X %02X) A: %02X B: %02X C: %02X\n", cpu.Regs.PC,
 | 
				
			||||||
			opcode, cpu.Bus.Read(cpu.Regs.PC+1), cpu.Bus.Read(cpu.Regs.PC+2), cpu.Regs.A, cpu.Regs.B, cpu.Regs.C)
 | 
								opcode, cpu.Bus.Read(cpu.Regs.PC), cpu.Bus.Read(cpu.Regs.PC+1), cpu.Regs.A, cpu.Regs.B, cpu.Regs.C)
 | 
				
			||||||
 | 
					 | 
				
			||||||
		cpu.Regs.PC++
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		switch opcode {
 | 
							switch opcode {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case 0x00:
 | 
							case 0x00:
 | 
				
			||||||
			// NOP
 | 
								// NOP
 | 
				
			||||||
 | 
					 | 
				
			||||||
		case 0x21:
 | 
					 | 
				
			||||||
			// LD HL, n16
 | 
					 | 
				
			||||||
			cpu.Regs.L = cpu.Bus.Read(cpu.Regs.PC)
 | 
					 | 
				
			||||||
			//     emu_cycles(1);
 | 
					 | 
				
			||||||
			cpu.Regs.H = cpu.Bus.Read(cpu.Regs.PC + 1)
 | 
					 | 
				
			||||||
			// emu_cycles(1);
 | 
					 | 
				
			||||||
			cpu.Regs.PC += 2
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		case 0x31:
 | 
					 | 
				
			||||||
			// LD SP, n16
 | 
					 | 
				
			||||||
			lo := cpu.Bus.Read(cpu.Regs.PC)
 | 
					 | 
				
			||||||
			//     emu_cycles(1);
 | 
					 | 
				
			||||||
			hi := cpu.Bus.Read(cpu.Regs.PC + 1)
 | 
					 | 
				
			||||||
			// emu_cycles(1);
 | 
					 | 
				
			||||||
			cpu.Regs.SP = uint16(lo) | uint16(hi)<<8
 | 
					 | 
				
			||||||
			cpu.Regs.PC += 2
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		case 0x3C:
 | 
							case 0x3C:
 | 
				
			||||||
			// INC A
 | 
								// INC A
 | 
				
			||||||
			cpu.Regs.A++
 | 
								cpu.Regs.A++
 | 
				
			||||||
@ -98,49 +75,19 @@ func (cpu *CPU) Step() {
 | 
				
			|||||||
			} else {
 | 
								} else {
 | 
				
			||||||
				cpu.ClearFlag(H)
 | 
									cpu.ClearFlag(H)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					 | 
				
			||||||
		case 0xCB:
 | 
					 | 
				
			||||||
			// Prefix byte instructions
 | 
					 | 
				
			||||||
			cbOpcode := cpu.Bus.Read(cpu.Regs.PC)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			fmt.Printf("%04X: (%02X %02X %02X) A: %02X B: %02X C: %02X\n", cpu.Regs.PC,
 | 
					 | 
				
			||||||
				cbOpcode, cpu.Bus.Read(cpu.Regs.PC+1), cpu.Bus.Read(cpu.Regs.PC+2), cpu.Regs.A, cpu.Regs.B, cpu.Regs.C)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			cpu.Regs.PC++
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			switch cbOpcode {
 | 
					 | 
				
			||||||
			default:
 | 
					 | 
				
			||||||
				fmt.Printf("\nINVALID INSTRUCTION! Unknown CB opcode: %02X\n", cbOpcode)
 | 
					 | 
				
			||||||
				os.Exit(1)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		case 0xC3:
 | 
							case 0xC3:
 | 
				
			||||||
			// JP a16
 | 
								// JP a16
 | 
				
			||||||
			lo := cpu.Bus.Read(cpu.Regs.PC)
 | 
								lo := cpu.Bus.Read(cpu.Regs.PC)
 | 
				
			||||||
			//     emu_cycles(1);
 | 
								//     emu_cycles(1);
 | 
				
			||||||
			hi := cpu.Bus.Read(cpu.Regs.PC + 1)
 | 
								hi := cpu.Bus.Read(cpu.Regs.PC + 1)
 | 
				
			||||||
			// emu_cycles(1);
 | 
								// emu_cycles(1);
 | 
				
			||||||
			cpu.Regs.PC = uint16(lo) | uint16(hi)<<8
 | 
								cpu.Regs.PC = uint16(hi)<<8 | uint16(lo)
 | 
				
			||||||
 | 
					 | 
				
			||||||
		case 0xCD:
 | 
					 | 
				
			||||||
			// CALL a16
 | 
					 | 
				
			||||||
			cpu.StackPush16(cpu.Regs.PC + 2)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			lo := cpu.Bus.Read(cpu.Regs.PC)
 | 
					 | 
				
			||||||
			//     emu_cycles(1);
 | 
					 | 
				
			||||||
			hi := cpu.Bus.Read(cpu.Regs.PC + 1)
 | 
					 | 
				
			||||||
			// emu_cycles(1);
 | 
					 | 
				
			||||||
			cpu.Regs.PC = uint16(lo) | uint16(hi)<<8
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case 0xE9:
 | 
							case 0xE9:
 | 
				
			||||||
			// JP HL
 | 
								// JP HL
 | 
				
			||||||
			val := uint16(cpu.Regs.H)<<8 | uint16(cpu.Regs.L)
 | 
								val := uint16(cpu.Regs.H)<<8 | uint16(cpu.Regs.L)
 | 
				
			||||||
			cpu.Regs.PC = val
 | 
								cpu.Regs.PC = val
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case 0xF3:
 | 
					 | 
				
			||||||
			// DI
 | 
					 | 
				
			||||||
			cpu.InterruptMasterEnable = false
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			fmt.Printf("\nINVALID INSTRUCTION! Unknown opcode: %02X\n", opcode)
 | 
								fmt.Printf("\nINVALID INSTRUCTION! Unknown opcode: %02X\n", opcode)
 | 
				
			||||||
			os.Exit(1)
 | 
								os.Exit(1)
 | 
				
			||||||
@ -163,27 +110,3 @@ func (cpu *CPU) ToggleFlag(flag CPUFlags) {
 | 
				
			|||||||
func (cpu *CPU) IsFlagSet(flag CPUFlags) bool {
 | 
					func (cpu *CPU) IsFlagSet(flag CPUFlags) bool {
 | 
				
			||||||
	return cpu.Regs.F&flag != 0
 | 
						return cpu.Regs.F&flag != 0
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
func (cpu *CPU) StackPush(data byte) {
 | 
					 | 
				
			||||||
	cpu.Regs.SP--
 | 
					 | 
				
			||||||
	cpu.Bus.Write(cpu.Regs.SP, data)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (cpu *CPU) StackPush16(data uint16) {
 | 
					 | 
				
			||||||
	cpu.StackPush(byte((data >> 8) & 0xFF))
 | 
					 | 
				
			||||||
	cpu.StackPush(byte(data & 0xFF))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (cpu *CPU) StackPop() byte {
 | 
					 | 
				
			||||||
	val := cpu.Bus.Read(cpu.Regs.SP)
 | 
					 | 
				
			||||||
	cpu.Regs.SP++
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return val
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (cpu *CPU) StackPop16() uint16 {
 | 
					 | 
				
			||||||
	lo := cpu.StackPop()
 | 
					 | 
				
			||||||
	hi := cpu.StackPop()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return uint16(hi)<<8 | uint16(lo)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -54,16 +54,16 @@ func TestInstruction00(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	cpu.Step()
 | 
						cpu.Step()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	assert.Equal(t, uint16(0x01), cpu.Regs.PC)
 | 
						assert.Equal(t, cpu.Regs.PC, uint16(0x01))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestInstruction3C(t *testing.T) {
 | 
					func TestInstruction3C(t *testing.T) {
 | 
				
			||||||
	// Should increment A register
 | 
						// Should increment A register
 | 
				
			||||||
	cpu := createCPU([]byte{0x3C, 0x00, 0x00})
 | 
						cpu := createCPU([]byte{0x3C, 0x00, 0x00})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	assert.Equal(t, byte(0x0), cpu.Regs.A)
 | 
						assert.Equal(t, cpu.Regs.A, byte(0x0))
 | 
				
			||||||
	cpu.Step()
 | 
						cpu.Step()
 | 
				
			||||||
	assert.Equal(t, byte(0x01), cpu.Regs.A)
 | 
						assert.Equal(t, cpu.Regs.A, byte(0x01))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Should clear Zero Flag
 | 
						// Should clear Zero Flag
 | 
				
			||||||
	cpu = createCPU([]byte{0x3C, 0x00, 0x00})
 | 
						cpu = createCPU([]byte{0x3C, 0x00, 0x00})
 | 
				
			||||||
@ -108,7 +108,7 @@ func TestInstructionC3(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	cpu.Step()
 | 
						cpu.Step()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	assert.Equal(t, uint16(0x150), cpu.Regs.PC)
 | 
						assert.Equal(t, cpu.Regs.PC, uint16(0x150))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestInstructionE9(t *testing.T) {
 | 
					func TestInstructionE9(t *testing.T) {
 | 
				
			||||||
@ -118,52 +118,5 @@ func TestInstructionE9(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	cpu.Step()
 | 
						cpu.Step()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	assert.Equal(t, uint16(0x1234), cpu.Regs.PC)
 | 
						assert.Equal(t, cpu.Regs.PC, uint16(0x1234))
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestInstructionF3(t *testing.T) {
 | 
					 | 
				
			||||||
	cpu := createCPU([]byte{0xF3, 0x00, 0x00})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	cpu.InterruptMasterEnable = true
 | 
					 | 
				
			||||||
	cpu.Step()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	assert.False(t, cpu.InterruptMasterEnable)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestInstruction31(t *testing.T) {
 | 
					 | 
				
			||||||
	cpu := createCPU([]byte{0x31, 0xFF, 0xCF})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	cpu.Step()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Should load SP with n16 value
 | 
					 | 
				
			||||||
	assert.Equal(t, uint16(0xCFFF), cpu.Regs.SP)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Should step over the 16 bit value onto the next instruction, i.e. increase the program counter with 3.
 | 
					 | 
				
			||||||
	assert.Equal(t, uint16(0x0003), cpu.Regs.PC)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestInstructionCD(t *testing.T) {
 | 
					 | 
				
			||||||
	cpu := createCPU([]byte{0xCD, 0x4C, 0x48, 0x41})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	cpu.Step()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Should push the address of the next instruction onto the stack
 | 
					 | 
				
			||||||
	// In this case 0x41 which is at address 0x03 (i.e. the 4th instruction in the row above creating the CPU instance)
 | 
					 | 
				
			||||||
	assert.Equal(t, uint16(0x03), cpu.Bus.Read16(cpu.Regs.SP))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Should jump to n16 value
 | 
					 | 
				
			||||||
	assert.Equal(t, uint16(0x484C), cpu.Regs.PC)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestInstruction21(t *testing.T) {
 | 
					 | 
				
			||||||
	cpu := createCPU([]byte{0x21, 0x34, 0x12})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	cpu.Step()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Should load the 16-bit immediate value into the combined HL register
 | 
					 | 
				
			||||||
	assert.Equal(t, byte(0x12), cpu.Regs.H)
 | 
					 | 
				
			||||||
	assert.Equal(t, byte(0x34), cpu.Regs.L)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Should increase the stack pointer
 | 
					 | 
				
			||||||
	assert.Equal(t, uint16(0x3), cpu.Regs.PC)
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										55
									
								
								gb/ram.go
									
									
									
									
									
								
							
							
						
						
									
										55
									
								
								gb/ram.go
									
									
									
									
									
								
							@ -1,55 +0,0 @@
 | 
				
			|||||||
package gb
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"fmt"
 | 
					 | 
				
			||||||
	"os"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
type RAM struct {
 | 
					 | 
				
			||||||
	WRAM [0x2000]byte
 | 
					 | 
				
			||||||
	HRAM [0x80]byte
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func NewRAM() *RAM {
 | 
					 | 
				
			||||||
	ram := RAM{}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return &ram
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (ram *RAM) WRAMRead(address uint16) byte {
 | 
					 | 
				
			||||||
	// TODO(m): Understand this line
 | 
					 | 
				
			||||||
	address -= 0xC000
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if address >= 0x2000 {
 | 
					 | 
				
			||||||
		fmt.Printf("Reading from WRAM: invalid address %X", address+0xC000)
 | 
					 | 
				
			||||||
		os.Exit(1)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return ram.WRAM[address]
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (ram *RAM) WRAMWrite(address uint16, value byte) {
 | 
					 | 
				
			||||||
	// TODO(m): Understand this line
 | 
					 | 
				
			||||||
	address -= 0xC000
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if address >= 0x2000 {
 | 
					 | 
				
			||||||
		fmt.Printf("Writing to WRAM: invalid address %X", address)
 | 
					 | 
				
			||||||
		os.Exit(1)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ram.WRAM[address] = value
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (ram *RAM) HRAMRead(address uint16) byte {
 | 
					 | 
				
			||||||
	// TODO(m): Understand this line
 | 
					 | 
				
			||||||
	address -= 0xFF80
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return ram.HRAM[address]
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func (ram *RAM) HRAMWrite(address uint16, value byte) {
 | 
					 | 
				
			||||||
	// TODO(m): Understand this line
 | 
					 | 
				
			||||||
	address -= 0xFF80
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	ram.HRAM[address] = value
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1,59 +0,0 @@
 | 
				
			|||||||
package gb
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import (
 | 
					 | 
				
			||||||
	"testing"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	"github.com/stretchr/testify/assert"
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestStackPush(t *testing.T) {
 | 
					 | 
				
			||||||
	cpu := createCPU([]byte{0x00, 0x00, 0x00})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	cpu.StackPush(0xDE)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Should decrement the stack pointer
 | 
					 | 
				
			||||||
	assert.Equal(t, cpu.Regs.SP, uint16(0xDFFE))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Should write the value to the stack
 | 
					 | 
				
			||||||
	assert.Equal(t, cpu.Bus.Read(cpu.Regs.SP), byte(0xDE))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestStackPush16(t *testing.T) {
 | 
					 | 
				
			||||||
	cpu := createCPU([]byte{0x00, 0x00, 0x00})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	cpu.StackPush16(0xDEAD)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Should decrement the stack pointer twice
 | 
					 | 
				
			||||||
	assert.Equal(t, cpu.Regs.SP, uint16(0xDFFD))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Should write the value to the stack
 | 
					 | 
				
			||||||
	assert.Equal(t, cpu.Bus.Read16(cpu.Regs.SP), uint16(0xDEAD))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestStackPop(t *testing.T) {
 | 
					 | 
				
			||||||
	cpu := createCPU([]byte{0x00, 0x00, 0x00})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	cpu.StackPush(0xDE)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	val := cpu.StackPop()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Should increment the stack pointer
 | 
					 | 
				
			||||||
	assert.Equal(t, cpu.Regs.SP, uint16(0xDFFF))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Should return the byte value
 | 
					 | 
				
			||||||
	assert.Equal(t, val, byte(0xDE))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
func TestStackPop16(t *testing.T) {
 | 
					 | 
				
			||||||
	cpu := createCPU([]byte{0x00, 0x00, 0x00})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	cpu.StackPush16(0xBEEF)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	val := cpu.StackPop16()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Should increment the stack pointer
 | 
					 | 
				
			||||||
	assert.Equal(t, cpu.Regs.SP, uint16(0xDFFF))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Should return the 16 bit value
 | 
					 | 
				
			||||||
	assert.Equal(t, val, uint16(0xBEEF))
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user