diff --git a/bus/bus.go b/bus/bus.go deleted file mode 100644 index 64c4885..0000000 --- a/bus/bus.go +++ /dev/null @@ -1,104 +0,0 @@ -// Package bus represents the 16-bit address and 8-bit data bus for the -// 6502. Different memory modules can be used for different addresses. -package bus - -import ( - "fmt" - "github.com/ariejan/i6502/memory" -) - -type busModule struct { - memory memory.Memory - name string - start uint16 - end uint16 -} - -// A 16-bit address and 8-bit data bus. It maps access to different -// attached modules, like Ram or Rom. -type Bus struct { - modules []busModule -} - -func (module busModule) String() string { - return fmt.Sprintf("%s\t0x%04X-%04X\n", module.name, module.start, module.end) -} - -func (bus *Bus) String() string { - output := "\n\nAddress bus modules:\n\n" - - for _, module := range bus.modules { - // output = append(output, module.String()) - output += module.String() - } - - return output -} - -// Creates a new Bus, no modules are attached by default. -func CreateBus() (*Bus, error) { - return &Bus{modules: make([]busModule, 0)}, nil -} - -func (bus *Bus) Attach(memory memory.Memory, name string, offset uint16) error { - offsetMemory := OffsetMemory{Offset: offset, Memory: memory} - end := offset + uint16(memory.Size()-1) - - module := busModule{memory: offsetMemory, name: name, start: offset, end: end} - - bus.modules = append(bus.modules, module) - - return nil -} - -func (bus *Bus) backendFor(address uint16) (memory.Memory, error) { - for _, module := range bus.modules { - if address >= module.start && address <= module.end { - return module.memory, nil - } - } - - return nil, fmt.Errorf("No module addressable at 0x%04X\n", address) -} - -// Read an 8-bit value from the module mapped on the bus at the -// given 16-bit address. -func (bus *Bus) Read(address uint16) byte { - memory, err := bus.backendFor(address) - if err != nil { - fmt.Printf("Reading from invalid address $%04X. Returning $00\n", address) - return 0x00 - // panic(err) - } - - value := memory.Read(address) - return value -} - -// Write an 8-bit value to the module mapped on the bus through the -// 16-bit address. -func (bus *Bus) Write(address uint16, value byte) { - memory, err := bus.backendFor(address) - if err != nil { - fmt.Printf("Writing to invalid address $%04X. Faking write.\n", address) - return - // panic(err) - } - - memory.Write(address, value) -} - -// Helper method to read a 16-bit value from -// Note: LSB goes first: address [lo] + address+1 [hi] -func (bus *Bus) Read16(address uint16) uint16 { - lo := uint16(bus.Read(address)) - hi := uint16(bus.Read(address + 1)) - return hi<<8 | lo -} - -// Helper to write a 16-bit value to address and address + 1 -// Note: LSB goes first: address [lo] + address+1 [hi] -func (bus *Bus) Write16(address uint16, value uint16) { - bus.Write(address, byte(value)) - bus.Write(address+1, byte(value>>8)) -} diff --git a/bus/offset_memory.go b/bus/offset_memory.go deleted file mode 100644 index 7de1bdd..0000000 --- a/bus/offset_memory.go +++ /dev/null @@ -1,20 +0,0 @@ -package bus - -import ( - "github.com/ariejan/i6502/memory" -) - -// The AddressDecoder routes a full 16-bit address to the -// appropriate relatie Memory component address. -type OffsetMemory struct { - Offset uint16 - memory.Memory -} - -func (offsetMemory OffsetMemory) Read(address uint16) byte { - return offsetMemory.Memory.Read(address - offsetMemory.Offset) -} - -func (offsetMemory OffsetMemory) Write(address uint16, value byte) { - offsetMemory.Memory.Write(address-offsetMemory.Offset, value) -} diff --git a/connection.go b/connection.go deleted file mode 100644 index 009024e..0000000 --- a/connection.go +++ /dev/null @@ -1,108 +0,0 @@ -package main - -import ( - "github.com/gorilla/websocket" - "log" - "net/http" - "time" -) - -const ( - pongWait = 60 * time.Second - pingPeriod = (pongWait * 9) / 10 - maxMessageSize = 512 -) - -type connection struct { - // The i6502 machine - machine *Machine - - // Websocket connection - ws *websocket.Conn - - // Outgoing data channel - send chan []byte -} - -var ( - upgrader = websocket.Upgrader{ - ReadBufferSize: 1024, - WriteBufferSize: 1024, - } -) - -// Pump received websocket messages into the machine -func (c *connection) readPump() { - defer func() { - c.ws.Close() - }() - - c.ws.SetReadLimit(maxMessageSize) - c.ws.SetReadDeadline(time.Now().Add(pongWait)) - c.ws.SetPongHandler(func(string) error { c.ws.SetReadDeadline(time.Now().Add(pongWait)); return nil }) - for { - _, message, err := c.ws.ReadMessage() - if err != nil { - break - } - c.writeBytesToMachine(message) - } -} - -// Pump serial output from the machine into the socket -func (c *connection) writePump() { - ticker := time.NewTicker(pingPeriod) - - defer func() { - c.ws.Close() - }() - - for { - select { - case data, ok := <-c.machine.SerialTx: - if !ok { - c.write(websocket.CloseMessage, []byte{}) - return - } - if err := c.write(websocket.TextMessage, []byte{data}); err != nil { - return - } - case <-ticker.C: - if err := c.write(websocket.PingMessage, []byte{}); err != nil { - return - } - } - } -} - -func (c *connection) write(messageType int, payload []byte) error { - c.ws.SetWriteDeadline(time.Now().Add(10 * time.Second)) - return c.ws.WriteMessage(messageType, payload) -} - -func (c *connection) writeBytesToMachine(data []byte) { - for _, b := range data { - log.Printf("%c", b) - c.machine.SerialRx <- b - } -} - -func serveWs(w http.ResponseWriter, r *http.Request) { - if r.Method != "GET" { - http.Error(w, "Method not allowed", 405) - return - } - - ws, err := upgrader.Upgrade(w, r, nil) - if err != nil { - log.Println(err) - return - } - - c := &connection{machine: CreateMachine(), send: make(chan []byte, 256), ws: ws} - - go c.writePump() - - c.machine.Reset() - c.readPump() -} diff --git a/cpu/cpu.go b/cpu/cpu.go deleted file mode 100644 index f810593..0000000 --- a/cpu/cpu.go +++ /dev/null @@ -1,721 +0,0 @@ -package cpu - -import ( - "fmt" - "github.com/ariejan/i6502/bus" - "strings" -) - -// Status register flags -const ( - sCarry = iota - sZero - sInterrupt - sDecimal - sBreak - _ - sOverflow - sNegative -) - -// Beginning of the stack. -// The stack grows downward, so it starts at 0x1FF -const ( - StackBase = 0x0100 - NmiVector = 0xFFFA // + 0xFFFB - ResetVector = 0xFFFC // + 0xFFFD - IrqVector = 0xFFFE // + 0xFFFF -) - -type Cpu struct { - // Program counter - PC uint16 - - // Accumulator - A byte - - // X, Y general purpose/index registers - X byte - Y byte - - // Stack pointer - SP byte - - // Status registers - SR byte - - // Memory bus - Bus *bus.Bus - - IrqChan chan bool - NmiChan chan bool - - // Handle exiting - ExitChan chan int -} - -// Reset the CPU, identical to triggering the RESB pin. -// This resets the status register and loads the _reset vector_ from -// address 0xFFFC into the Program Counter. Note this is a 16 bit value, read from -// 0xFFFC-FFFD -func (c *Cpu) Reset() { - c.PC = c.Bus.Read16(ResetVector) - c.SR = 0x34 -} - -func (c *Cpu) String() string { - return fmt.Sprintf( - "CPU PC:0x%04X A:0x%02X X:0x%02X Y:0x%02X SP:0x%02X SR:%s", - c.PC, c.A, c.X, c.Y, c.SP, - c.statusString(), - ) -} - -func (c *Cpu) handleIrq(returnPC uint16) { - c.handleInterrupt(returnPC, IrqVector) -} - -func (c *Cpu) handleNmi() { - c.handleInterrupt(c.PC, NmiVector) -} - -func (c *Cpu) handleInterrupt(returnPC uint16, vector uint16) { - c.setStatus(sBreak, true) - - // Push PC + 1 onto stack - c.stackPush(byte(returnPC >> 8)) - c.stackPush(byte(returnPC)) - // Push status register to the stack - c.stackPush(c.SR) - - // Disable interrupts - c.setStatus(sInterrupt, true) - - c.PC = c.Bus.Read16(vector) -} - -func (c *Cpu) stackPush(data byte) { - c.Bus.Write(StackBase+uint16(c.SP), data) - c.SP-- -} - -func (c *Cpu) stackPop() byte { - c.SP++ - return c.Bus.Read(StackBase + uint16(c.SP)) -} - -func (c *Cpu) Step() { - select { - case <-c.IrqChan: - if !c.getStatus(sInterrupt) { - // Handle interrupt - c.handleIrq(c.PC) - } - case <-c.NmiChan: - c.handleNmi() - default: - // Read the instruction (including operands) - instruction := ReadInstruction(c.PC, c.Bus) - - // Move the Program Counter forward, depending - // on the size of the optype we just read. - c.PC += uint16(instruction.Bytes) - - fmt.Printf(instruction.String()) - - // Execute the instruction - c.execute(instruction) - } -} - -func (c *Cpu) stackHead(offset int8) uint16 { - address := uint16(StackBase) + uint16(c.SP) + uint16(offset) - val8 := c.Bus.Read(address) - val16 := c.Bus.Read16(address) - fmt.Printf("Addressing Stack at 0x%04X (8: 0x%02X; 16: 0x%04X from PC 0x%04X\n", address, val8, val16, c.PC) - return address -} - -func (c *Cpu) resolveOperand(in Instruction) uint8 { - switch in.addressing { - case immediate: - return in.Op8 - default: - return c.Bus.Read(c.memoryAddress(in)) - } -} - -func (c *Cpu) memoryAddress(in Instruction) uint16 { - switch in.addressing { - case absolute: - return in.Op16 - case absoluteX: - return in.Op16 + uint16(c.X) - case absoluteY: - return in.Op16 + uint16(c.Y) - - case indirect: - location := uint16(in.Op16) - return c.Bus.Read16(location) - - // Indexed Indirect (X) - // Operand is the zero-page location of a little-endian 16-bit base address. - // The X register is added (wrapping; discarding overflow) before loading. - // The resulting address loaded from (base+X) becomes the effective operand. - // (base + X) must be in zero-page. - case indirectX: - location := uint16(in.Op8 + c.X) - if location == 0xFF { - panic("Indexed indirect high-byte not on zero page.") - } - return c.Bus.Read16(location) - - // Indirect Indexed (Y) - // Operand is the zero-page location of a little-endian 16-bit address. - // The address is loaded, and then the Y register is added to it. - // The resulting loaded_address + Y becomes the effective operand. - case indirectY: - return c.Bus.Read16(uint16(in.Op8)) + uint16(c.Y) - - case zeropage: - return uint16(in.Op8) - case zeropageX: - return uint16(in.Op8 + c.X) - case zeropageY: - return uint16(in.Op8 + c.Y) - default: - panic(fmt.Errorf("Unhandled addressing mode: 0x%02X (%s). Are you sure your rom is compatible?", in.addressing, addressingNames[in.addressing])) - } -} - -func (c *Cpu) getStatus(bit uint8) bool { - return c.getStatusInt(bit) == 1 -} - -func (c *Cpu) getStatusInt(bit uint8) uint8 { - return (c.SR >> bit) & 1 -} - -func (c *Cpu) setStatus(bit uint8, state bool) { - if state { - c.SR |= 1 << bit - } else { - c.SR &^= 1 << bit - } -} - -func (c *Cpu) updateStatus(value uint8) { - c.setStatus(sZero, value == 0) - c.setStatus(sNegative, (value>>7) == 1) -} - -func (c *Cpu) statusString() string { - chars := "nv_bdizc" - out := make([]string, 8) - for i := 0; i < 8; i++ { - if c.getStatus(uint8(7 - i)) { - out[i] = string(chars[i]) - } else { - out[i] = "-" - } - } - return strings.Join(out, "") -} - -func (c *Cpu) branch(in Instruction) { - relative := int8(in.Op8) // signed - if relative >= 0 { - c.PC += uint16(relative) - } else { - c.PC -= uint16(-relative) - } -} - -func (c *Cpu) execute(in Instruction) { - switch in.id { - case adc: - c.ADC(in) - case and: - c.AND(in) - case asl: - c.ASL(in) - case bcc: - c.BCC(in) - case bcs: - c.BCS(in) - case beq: - c.BEQ(in) - case bmi: - c.BMI(in) - case bne: - c.BNE(in) - case bpl: - c.BPL(in) - case brk: - c.BRK(in) - case clc: - c.CLC(in) - case cld: - c.CLD(in) - case cli: - c.CLI(in) - case cmp: - c.CMP(in) - case cpx: - c.CPX(in) - case cpy: - c.CPY(in) - case dec: - c.DEC(in) - case dex: - c.DEX(in) - case dey: - c.DEY(in) - case eor: - c.EOR(in) - case inc: - c.INC(in) - case inx: - c.INX(in) - case iny: - c.INY(in) - case jmp: - c.JMP(in) - case jsr: - c.JSR(in) - case lda: - c.LDA(in) - case ldx: - c.LDX(in) - case ldy: - c.LDY(in) - case lsr: - c.LSR(in) - case nop: - c.NOP(in) - case ora: - c.ORA(in) - case pha: - c.PHA(in) - case php: - c.PHP(in) - case pla: - c.PLA(in) - case plp: - c.PLP(in) - case rol: - c.ROL(in) - case ror: - c.ROR(in) - case rti: - c.RTI(in) - case rts: - c.RTS(in) - case sbc: - c.SBC(in) - case sec: - c.SEC(in) - case sei: - c.SEI(in) - case sta: - c.STA(in) - case stx: - c.STX(in) - case sty: - c.STY(in) - case tax: - c.TAX(in) - case tay: - c.TAY(in) - case tsx: - c.TSX(in) - case txa: - c.TXA(in) - case txs: - c.TXS(in) - case tya: - c.TYA(in) - case _end: - c._END(in) - default: - panic(fmt.Sprintf("Unhandled instruction: %X", in.OpType)) - } -} - -// ADC: Add memory and carry to accumulator. -func (c *Cpu) ADC(in Instruction) { - value16 := uint16(c.A) + uint16(c.resolveOperand(in)) + uint16(c.getStatusInt(sCarry)) - c.setStatus(sCarry, value16 > 0xFF) - c.A = uint8(value16) - c.updateStatus(c.A) -} - -// AND: And accumulator with memory. -func (c *Cpu) AND(in Instruction) { - c.A &= c.resolveOperand(in) - c.updateStatus(c.A) -} - -// ASL: Shift memory or accumulator left one bit. -func (c *Cpu) ASL(in Instruction) { - switch in.addressing { - case accumulator: - c.setStatus(sCarry, (c.A>>7) == 1) // carry = old bit 7 - c.A <<= 1 - c.updateStatus(c.A) - default: - address := c.memoryAddress(in) - value := c.Bus.Read(address) - c.setStatus(sCarry, (value>>7) == 1) // carry = old bit 7 - value <<= 1 - c.Bus.Write(address, value) - c.updateStatus(value) - } -} - -// BCC: Branch if carry clear. -func (c *Cpu) BCC(in Instruction) { - if !c.getStatus(sCarry) { - c.branch(in) - } -} - -// BCS: Branch if carry set. -func (c *Cpu) BCS(in Instruction) { - if c.getStatus(sCarry) { - c.branch(in) - } -} - -// BEQ: Branch if equal (z=1). -func (c *Cpu) BEQ(in Instruction) { - if c.getStatus(sZero) { - c.branch(in) - } -} - -// BMI: Branch if negative. -func (c *Cpu) BMI(in Instruction) { - if c.getStatus(sNegative) { - c.branch(in) - } -} - -// BNE: Branch if not equal. -func (c *Cpu) BNE(in Instruction) { - if !c.getStatus(sZero) { - c.branch(in) - } -} - -// BPL: Branch if positive. -func (c *Cpu) BPL(in Instruction) { - if !c.getStatus(sNegative) { - c.branch(in) - } -} - -// BRK: software interrupt -func (c *Cpu) BRK(in Instruction) { - fmt.Println("BRK:", c) - c.ExitChan <- 42 - - // Force interrupt - // if !c.getStatus(sInterrupt) { - // c.handleIrq(c.PC + 1) - // } -} - -// CLC: Clear carry flag. -func (c *Cpu) CLC(in Instruction) { - c.setStatus(sCarry, false) -} - -// CLD: Clear decimal mode flag. -func (c *Cpu) CLD(in Instruction) { - c.setStatus(sDecimal, false) -} - -// CLI: Clear interrupt-disable flag. -func (c *Cpu) CLI(in Instruction) { - c.setStatus(sInterrupt, true) -} - -// CMP: Compare accumulator with memory. -func (c *Cpu) CMP(in Instruction) { - value := c.resolveOperand(in) - c.setStatus(sCarry, c.A >= value) - c.updateStatus(c.A - value) -} - -// CPX: Compare index register X with memory. -func (c *Cpu) CPX(in Instruction) { - value := c.resolveOperand(in) - c.setStatus(sCarry, c.X >= value) - c.updateStatus(c.X - value) -} - -// CPY: Compare index register Y with memory. -func (c *Cpu) CPY(in Instruction) { - value := c.resolveOperand(in) - c.setStatus(sCarry, c.Y >= value) - c.updateStatus(c.Y - value) -} - -// DEC: Decrement. -func (c *Cpu) DEC(in Instruction) { - address := c.memoryAddress(in) - value := c.Bus.Read(address) - 1 - c.Bus.Write(address, value) - c.updateStatus(value) -} - -// DEX: Decrement index register X. -func (c *Cpu) DEX(in Instruction) { - c.X-- - c.updateStatus(c.X) -} - -// DEY: Decrement index register Y. -func (c *Cpu) DEY(in Instruction) { - c.Y-- - c.updateStatus(c.Y) -} - -// EOR: Exclusive-OR accumulator with memory. -func (c *Cpu) EOR(in Instruction) { - value := c.resolveOperand(in) - c.A ^= value - c.updateStatus(c.A) -} - -// INC: Increment. -func (c *Cpu) INC(in Instruction) { - address := c.memoryAddress(in) - value := c.Bus.Read(address) + 1 - c.Bus.Write(address, value) - c.updateStatus(value) -} - -// INX: Increment index register X. -func (c *Cpu) INX(in Instruction) { - c.X++ - c.updateStatus(c.X) -} - -// INY: Increment index register Y. -func (c *Cpu) INY(in Instruction) { - c.Y++ - c.updateStatus(c.Y) -} - -// JMP: Jump. -func (c *Cpu) JMP(in Instruction) { - c.PC = c.memoryAddress(in) -} - -// JSR: Jump to subroutine. -func (c *Cpu) JSR(in Instruction) { - c.Bus.Write16(c.stackHead(-1), c.PC-1) - c.SP -= 2 - c.PC = in.Op16 -} - -// LDA: Load accumulator from memory. -func (c *Cpu) LDA(in Instruction) { - c.A = c.resolveOperand(in) - c.updateStatus(c.A) -} - -// LDX: Load index register X from memory. -func (c *Cpu) LDX(in Instruction) { - c.X = c.resolveOperand(in) - c.updateStatus(c.X) -} - -// LDY: Load index register Y from memory. -func (c *Cpu) LDY(in Instruction) { - c.Y = c.resolveOperand(in) - c.updateStatus(c.Y) -} - -// LSR: Logical shift memory or accumulator right. -func (c *Cpu) LSR(in Instruction) { - switch in.addressing { - case accumulator: - c.setStatus(sCarry, c.A&1 == 1) - c.A >>= 1 - c.updateStatus(c.A) - default: - address := c.memoryAddress(in) - value := c.Bus.Read(address) - c.setStatus(sCarry, value&1 == 1) - value >>= 1 - c.Bus.Write(address, value) - c.updateStatus(value) - } -} - -// NOP: No operation. -func (c *Cpu) NOP(in Instruction) { -} - -// ORA: OR accumulator with memory. -func (c *Cpu) ORA(in Instruction) { - c.A |= c.resolveOperand(in) - c.updateStatus(c.A) -} - -// PHA: Push accumulator onto stack. -func (c *Cpu) PHA(in Instruction) { - c.stackPush(c.A) -} - -// PHP: Push SR to stack -func (c *Cpu) PHP(in Instruction) { - c.stackPush(c.SR) -} - -// PLA: Pull accumulator from stack. -func (c *Cpu) PLA(in Instruction) { - c.A = c.stackPop() -} - -// PLP: Pull SR from stack -func (c *Cpu) PLP(in Instruction) { - c.SR = c.stackPop() -} - -// ROL: Rotate memory or accumulator left one bit. -func (c *Cpu) ROL(in Instruction) { - carry := c.getStatusInt(sCarry) - switch in.addressing { - case accumulator: - c.setStatus(sCarry, c.A>>7 == 1) - c.A = c.A<<1 | carry - c.updateStatus(c.A) - default: - address := c.memoryAddress(in) - value := c.Bus.Read(address) - c.setStatus(sCarry, value>>7 == 1) - value = value<<1 | carry - c.Bus.Write(address, value) - c.updateStatus(value) - } -} - -// ROR: Rotate memory or accumulator left one bit. -func (c *Cpu) ROR(in Instruction) { - carry := c.getStatusInt(sCarry) - switch in.addressing { - case accumulator: - c.setStatus(sCarry, c.A&1 == 1) - c.A = c.A>>1 | carry<<7 - c.updateStatus(c.A) - default: - address := c.memoryAddress(in) - value := c.Bus.Read(address) - c.setStatus(sCarry, value&1 == 1) - value = value>>1 | carry<<7 - c.Bus.Write(address, value) - c.updateStatus(value) - } -} - -// RTI: Return from interrupt -func (c *Cpu) RTI(in Instruction) { - c.SR = c.stackPop() - c.PC = c.Bus.Read16(c.stackHead(1)) - c.SP += 2 - fmt.Printf("RTI: Returning to 0x%04X", c.PC) -} - -// RTS: Return from subroutine. -func (c *Cpu) RTS(in Instruction) { - c.PC = c.Bus.Read16(c.stackHead(1)) + 1 - c.SP += 2 -} - -// SBC: Subtract memory with borrow from accumulator. -func (c *Cpu) SBC(in Instruction) { - valueSigned := int16(c.A) - int16(c.resolveOperand(in)) - if !c.getStatus(sCarry) { - valueSigned-- - } - c.A = uint8(valueSigned) - - // v: Set if signed overflow; cleared if valid sign result. - // TODO: c.setStatus(sOverflow, something) - - // c: Set if unsigned borrow not required; cleared if unsigned borrow. - c.setStatus(sCarry, valueSigned >= 0) - - // n: Set if most significant bit of result is set; else cleared. - // z: Set if result is zero; else cleared. - c.updateStatus(c.A) -} - -// SEC: Set carry flag. -func (c *Cpu) SEC(in Instruction) { - c.setStatus(sCarry, true) -} - -// SEI: Set interrupt-disable flag. -func (c *Cpu) SEI(in Instruction) { - c.setStatus(sInterrupt, false) -} - -// STA: Store accumulator to memory. -func (c *Cpu) STA(in Instruction) { - c.Bus.Write(c.memoryAddress(in), c.A) -} - -// STX: Store index register X to memory. -func (c *Cpu) STX(in Instruction) { - c.Bus.Write(c.memoryAddress(in), c.X) -} - -// STY: Store index register Y to memory. -func (c *Cpu) STY(in Instruction) { - c.Bus.Write(c.memoryAddress(in), c.Y) -} - -// TAX: Transfer accumulator to index register X. -func (c *Cpu) TAX(in Instruction) { - c.X = c.A - c.updateStatus(c.X) -} - -// TAY: Transfer accumulator to index register Y. -func (c *Cpu) TAY(in Instruction) { - c.Y = c.A - c.updateStatus(c.Y) -} - -// TSX: Transfer stack pointer to index register X. -func (c *Cpu) TSX(in Instruction) { - c.X = c.SP - c.updateStatus(c.X) -} - -// TXA: Transfer index register X to accumulator. -func (c *Cpu) TXA(in Instruction) { - c.A = c.X - c.updateStatus(c.A) -} - -// TXS: Transfer index register X to stack pointer. -func (c *Cpu) TXS(in Instruction) { - c.SP = c.X - c.updateStatus(c.SP) -} - -// TYA: Transfer index register Y to accumulator. -func (c *Cpu) TYA(in Instruction) { - c.A = c.Y - c.updateStatus(c.A) -} - -func (c *Cpu) _END(in Instruction) { - c.ExitChan <- int(c.X) -} diff --git a/cpu/instruction.go b/cpu/instruction.go deleted file mode 100644 index 5088a10..0000000 --- a/cpu/instruction.go +++ /dev/null @@ -1,57 +0,0 @@ -package cpu - -import ( - "fmt" - "github.com/ariejan/i6502/bus" -) - -// Instruction is a self-contained, variable length instruction, -// it includes the the operation type and a possible 8 or 16 bit operand. -type Instruction struct { - OpType - - // 2 byte instructions have a single byte operand - Op8 uint8 - - // 3 byte instruction have a double byte operand - Op16 uint16 -} - -func (i *Instruction) String() string { - var output string - - switch i.Bytes { - case 1: - output = fmt.Sprintf("0x%02X - %s\n", i.Opcode, instructionNames[i.id]) - case 2: - output = fmt.Sprintf("0x%02X - %s %02X\n", i.Opcode, instructionNames[i.id], i.Op8) - case 3: - output = fmt.Sprintf("0x%02X - %s %04X\n", i.Opcode, instructionNames[i.id], i.Op16) - } - - return output -} - -func ReadInstruction(pc uint16, bus *bus.Bus) Instruction { - // Read the opcode - opcode := bus.Read(pc) - - // Do we know this opcode in our optypes table? - optype, ok := optypes[opcode] - if !ok { - panic(fmt.Sprintf("Unknown opcode $%02X at $%04X", opcode, pc)) - } - - instruction := Instruction{OpType: optype} - switch instruction.Bytes { - case 1: // No operand. - case 2: - instruction.Op8 = bus.Read(pc + 1) - case 3: - instruction.Op16 = bus.Read16(pc + 1) - default: - panic(fmt.Sprintf("Unknown instruction length (%d) for $%02X at $04X", instruction.Bytes, opcode, pc)) - } - - return instruction -} diff --git a/cpu/op_type.go b/cpu/op_type.go deleted file mode 100644 index 104f198..0000000 --- a/cpu/op_type.go +++ /dev/null @@ -1,340 +0,0 @@ -package cpu - -// 6502 Addressing modes -const ( - _ = iota - absolute - absoluteX - absoluteY - accumulator - immediate - implied - indirect - indirectX - indirectY - relative - zeropage - zeropageX - zeropageY -) - -// Human readable address modes -var addressingNames = [...]string{ - "", - "absolute", - "absoluteX", - "absoluteY", - "accumulator", - "immediate", - "implied", - "(indirect)", - "(indirect,X)", - "(indirect),Y", - "relative", - "zeropage", - "zeropageX", - "zeropageY", -} - -// 6502 Instruction mnemonics. -// OpCodes are a combination of an instruction and an addressing mode -const ( - _ = iota - adc - and - asl - bcc - bcs - beq - bit - bmi - bne - bpl - brk - bvc - bvs - clc - cld - cli - clv - cmp - cpx - cpy - dec - dex - dey - eor - inc - inx - iny - jmp - jsr - lda - ldx - ldy - lsr - nop - ora - pha - php - pla - plp - rol - ror - rti - rts - sbc - sec - sed - sei - sta - stx - sty - tax - tay - tsx - txa - txs - tya - _end -) - -// Human readable instruction mnemonics -var instructionNames = [...]string{ - "", - "ADC", - "AND", - "ASL", - "BCC", - "BCS", - "BEQ", - "BIT", - "BMI", - "BNE", - "BPL", - "BRK", - "BVC", - "BVS", - "CLC", - "CLD", - "CLI", - "CLV", - "CMP", - "CPX", - "CPY", - "DEC", - "DEX", - "DEY", - "EOR", - "INC", - "INX", - "INY", - "JMP", - "JSR", - "LDA", - "LDX", - "LDY", - "LSR", - "NOP", - "ORA", - "PHA", - "PHP", - "PLA", - "PLP", - "ROL", - "ROR", - "RTI", - "RTS", - "SBC", - "SEC", - "SED", - "SEI", - "STA", - "STX", - "STY", - "TAX", - "TAY", - "TSX", - "TXA", - "TXS", - "TYA", - "_END", -} - -// The OpType consists of a 6502 instruction and addressing mode. -// It does not include any following operand -type OpType struct { - // Opcode is the instruction + addresing mode - Opcode byte - - // Internal id for the used instruction/mnemonic - id uint8 - - // Internal id for the addressing mode - addressing uint8 - - // Bytes is the size of the instruction and its expected operands. - // 1 byte: opcode with implicit or null operand - // 2 bytes: opcode with immediate or zeropage operand (8-bit operand) - // 3 bytes: opcode with address operands - Bytes uint8 - - // Cycles, number of clock cycles it takes to execute this opcode - Cycles uint8 -} - -// See http://www.e-tradition.net/bytes/6502/6502_instruction_set.html for details -var optypes = map[uint8]OpType{ - 0x69: OpType{0x69, adc, immediate, 2, 2}, - 0x65: OpType{0x69, adc, zeropage, 2, 3}, - 0x75: OpType{0x75, adc, zeropageX, 2, 4}, - 0x6D: OpType{0x6D, adc, absolute, 3, 4}, - 0x7D: OpType{0x7D, adc, absoluteX, 3, 4}, - 0x79: OpType{0x79, adc, absoluteY, 3, 4}, - 0x61: OpType{0x61, adc, indirectX, 2, 6}, - 0x71: OpType{0x71, adc, indirectY, 2, 5}, - 0x29: OpType{0x29, and, immediate, 2, 2}, - 0x25: OpType{0x25, and, zeropage, 2, 3}, - 0x35: OpType{0x35, and, zeropageX, 2, 4}, - 0x2D: OpType{0x2D, and, absolute, 3, 4}, - 0x3D: OpType{0x3D, and, absoluteX, 3, 4}, - 0x39: OpType{0x39, and, absoluteY, 3, 4}, - 0x21: OpType{0x21, and, indirectX, 2, 6}, - 0x31: OpType{0x31, and, indirectY, 2, 5}, - 0x0A: OpType{0x0A, asl, accumulator, 1, 2}, - 0x06: OpType{0x06, asl, zeropage, 2, 5}, - 0x16: OpType{0x16, asl, zeropageX, 2, 6}, - 0x0E: OpType{0x0E, asl, absolute, 3, 6}, - 0x1E: OpType{0x1E, asl, absoluteX, 3, 7}, - 0x90: OpType{0x90, bcc, relative, 2, 2}, - 0xB0: OpType{0xB0, bcs, relative, 2, 2}, - 0xF0: OpType{0xF0, beq, relative, 2, 2}, - 0x24: OpType{0x24, bit, zeropage, 2, 3}, - 0x2C: OpType{0x2C, bit, absolute, 3, 4}, - 0x30: OpType{0x30, bmi, relative, 2, 2}, - 0xD0: OpType{0xD0, bne, relative, 2, 2}, - 0x10: OpType{0x10, bpl, relative, 2, 2}, - 0x00: OpType{0x00, brk, implied, 1, 7}, - 0x50: OpType{0x50, bvc, relative, 2, 2}, - 0x70: OpType{0x70, bvs, relative, 2, 2}, - 0x18: OpType{0x18, clc, implied, 1, 2}, - 0xD8: OpType{0xD8, cld, implied, 1, 2}, - 0x58: OpType{0x58, cli, implied, 1, 2}, - 0xB8: OpType{0xB8, clv, implied, 1, 2}, - 0xC9: OpType{0xC9, cmp, immediate, 2, 2}, - 0xC5: OpType{0xC5, cmp, zeropage, 2, 3}, - 0xD5: OpType{0xD5, cmp, zeropageX, 2, 4}, - 0xCD: OpType{0xCD, cmp, absolute, 3, 4}, - 0xDD: OpType{0xDD, cmp, absoluteX, 3, 4}, - 0xD9: OpType{0xD9, cmp, absoluteY, 3, 4}, - 0xC1: OpType{0xC1, cmp, indirectX, 2, 6}, - 0xD1: OpType{0xD1, cmp, indirectY, 2, 5}, - 0xE0: OpType{0xE0, cpx, immediate, 2, 2}, - 0xE4: OpType{0xE4, cpx, zeropage, 2, 3}, - 0xEC: OpType{0xEC, cpx, absolute, 3, 4}, - 0xC0: OpType{0xC0, cpy, immediate, 2, 2}, - 0xC4: OpType{0xC4, cpy, zeropage, 2, 3}, - 0xCC: OpType{0xCC, cpy, absolute, 3, 4}, - 0xC6: OpType{0xC6, dec, zeropage, 2, 5}, - 0xD6: OpType{0xD6, dec, zeropageX, 2, 6}, - 0xCE: OpType{0xCE, dec, absolute, 3, 3}, - 0xDE: OpType{0xDE, dec, absoluteX, 3, 7}, - 0xCA: OpType{0xCA, dex, implied, 1, 2}, - 0x88: OpType{0x88, dey, implied, 1, 2}, - 0x49: OpType{0x49, eor, immediate, 2, 2}, - 0x45: OpType{0x45, eor, zeropage, 2, 3}, - 0x55: OpType{0x55, eor, zeropageX, 2, 4}, - 0x4D: OpType{0x4D, eor, absolute, 3, 4}, - 0x5D: OpType{0x5D, eor, absoluteX, 3, 4}, - 0x59: OpType{0x59, eor, absoluteY, 3, 4}, - 0x41: OpType{0x41, eor, indirectX, 2, 6}, - 0x51: OpType{0x51, eor, indirectY, 2, 5}, - 0xE6: OpType{0xE6, inc, zeropage, 2, 5}, - 0xF6: OpType{0xF6, inc, zeropageX, 2, 6}, - 0xEE: OpType{0xEE, inc, absolute, 3, 6}, - 0xFE: OpType{0xFE, inc, absoluteX, 3, 7}, - 0xE8: OpType{0xE8, inx, implied, 1, 2}, - 0xC8: OpType{0xC8, iny, implied, 1, 2}, - 0x4C: OpType{0x4C, jmp, absolute, 3, 3}, - 0x6C: OpType{0x6C, jmp, indirect, 3, 5}, - 0x20: OpType{0x20, jsr, absolute, 3, 6}, - 0xA9: OpType{0xA9, lda, immediate, 2, 2}, - 0xA5: OpType{0xA5, lda, zeropage, 2, 3}, - 0xB5: OpType{0xB5, lda, zeropageX, 2, 4}, - 0xAD: OpType{0xAD, lda, absolute, 3, 4}, - 0xBD: OpType{0xBD, lda, absoluteX, 3, 4}, - 0xB9: OpType{0xB9, lda, absoluteY, 3, 4}, - 0xA1: OpType{0xA1, lda, indirectX, 2, 6}, - 0xB1: OpType{0xB1, lda, indirectY, 2, 5}, - 0xA2: OpType{0xA2, ldx, immediate, 2, 2}, - 0xA6: OpType{0xA6, ldx, zeropage, 2, 3}, - 0xB6: OpType{0xB6, ldx, zeropageY, 2, 4}, - 0xAE: OpType{0xAE, ldx, absolute, 3, 4}, - 0xBE: OpType{0xBE, ldx, absoluteY, 3, 4}, - 0xA0: OpType{0xA0, ldy, immediate, 2, 2}, - 0xA4: OpType{0xA4, ldy, zeropage, 2, 3}, - 0xB4: OpType{0xB4, ldy, zeropageX, 2, 4}, - 0xAC: OpType{0xAC, ldy, absolute, 3, 4}, - 0xBC: OpType{0xBC, ldy, absoluteX, 3, 4}, - 0x4A: OpType{0x4A, lsr, accumulator, 1, 2}, - 0x46: OpType{0x46, lsr, zeropage, 2, 5}, - 0x56: OpType{0x56, lsr, zeropageX, 2, 6}, - 0x4E: OpType{0x4E, lsr, absolute, 3, 6}, - 0x5E: OpType{0x5E, lsr, absoluteX, 3, 7}, - 0xEA: OpType{0xEA, nop, implied, 1, 2}, - 0x09: OpType{0x09, ora, immediate, 2, 2}, - 0x05: OpType{0x05, ora, zeropage, 2, 3}, - 0x15: OpType{0x15, ora, zeropageX, 2, 4}, - 0x0D: OpType{0x0D, ora, absolute, 3, 4}, - 0x1D: OpType{0x1D, ora, absoluteX, 3, 4}, - 0x19: OpType{0x19, ora, absoluteY, 3, 4}, - 0x01: OpType{0x01, ora, indirectX, 2, 6}, - 0x11: OpType{0x11, ora, indirectY, 2, 5}, - 0x48: OpType{0x48, pha, implied, 1, 3}, - 0x08: OpType{0x08, php, implied, 1, 3}, - 0x68: OpType{0x68, pla, implied, 1, 4}, - 0x28: OpType{0x28, php, implied, 1, 4}, - 0x2A: OpType{0x2A, rol, accumulator, 1, 2}, - 0x26: OpType{0x26, rol, zeropage, 2, 5}, - 0x36: OpType{0x36, rol, zeropageX, 2, 6}, - 0x2E: OpType{0x2E, rol, absolute, 3, 6}, - 0x3E: OpType{0x3E, rol, absoluteX, 3, 7}, - 0x6A: OpType{0x6A, ror, accumulator, 1, 2}, - 0x66: OpType{0x66, ror, zeropage, 2, 5}, - 0x76: OpType{0x76, ror, zeropageX, 2, 6}, - 0x6E: OpType{0x6E, ror, absolute, 3, 6}, - 0x7E: OpType{0x7E, ror, absoluteX, 3, 7}, - 0x40: OpType{0x40, rti, implied, 1, 6}, - 0x60: OpType{0x60, rts, implied, 1, 6}, - 0xE9: OpType{0xE9, sbc, immediate, 2, 2}, - 0xE5: OpType{0xE5, sbc, zeropage, 2, 3}, - 0xF5: OpType{0xF5, sbc, zeropageX, 2, 4}, - 0xED: OpType{0xED, sbc, absolute, 3, 4}, - 0xFD: OpType{0xFD, sbc, absoluteX, 3, 4}, - 0xF9: OpType{0xF9, sbc, absoluteY, 3, 4}, - 0xE1: OpType{0xE1, sbc, indirectX, 2, 6}, - 0xF1: OpType{0xF1, sbc, indirectY, 2, 5}, - 0x38: OpType{0x38, sec, implied, 1, 2}, - 0xF8: OpType{0xF8, sed, implied, 1, 2}, - 0x78: OpType{0x78, sei, implied, 1, 2}, - 0x85: OpType{0x85, sta, zeropage, 2, 3}, - 0x95: OpType{0x95, sta, zeropageX, 2, 4}, - 0x8D: OpType{0x8D, sta, absolute, 3, 4}, - 0x9D: OpType{0x9D, sta, absoluteX, 3, 5}, - 0x99: OpType{0x99, sta, absoluteY, 3, 5}, - 0x81: OpType{0x81, sta, indirectX, 2, 6}, - 0x91: OpType{0x91, sta, indirectY, 2, 6}, - 0x86: OpType{0x86, stx, zeropage, 2, 3}, - 0x96: OpType{0x96, stx, zeropageY, 2, 4}, - 0x8E: OpType{0x8E, stx, absolute, 3, 4}, - 0x84: OpType{0x84, sty, zeropage, 2, 3}, - 0x94: OpType{0x94, sty, zeropageX, 2, 4}, - 0x8C: OpType{0x8C, sty, absolute, 3, 4}, - 0xAA: OpType{0xAA, tax, implied, 1, 2}, - 0xA8: OpType{0xA8, tay, implied, 1, 2}, - 0xBA: OpType{0xBA, tsx, implied, 1, 2}, - 0x8A: OpType{0x8A, txa, implied, 1, 2}, - 0x9A: OpType{0x9A, txs, implied, 1, 2}, - 0x98: OpType{0x98, tya, implied, 1, 2}, - 0xFF: OpType{0xFF, _end, implied, 1, 1}, -} diff --git a/devices/acia6551.go b/devices/acia6551.go deleted file mode 100644 index 42e675d..0000000 --- a/devices/acia6551.go +++ /dev/null @@ -1,208 +0,0 @@ -package devices - -import ( - "fmt" - "time" -) - -const ( - aciaData = iota - aciaStatus - aciaCommand - aciaControl -) - -var baudRateSelectors = [...]int{0, 50, 75, 110, 135, 150, 300, 600, 1200, 1800, 2400, 3600, 4800, 7200, 9600, 19200} - -type Acia6551 struct { - // Registers - rx byte - tx byte - commandRegister byte - controlRegister byte - - // Other required bits and pieces - lastTxWrite int64 - lastRxRead int64 - overrun bool - baudRate int - baudRateDelay int64 - rxFull bool - txEmpty bool - - rxInterruptEnabled bool - txInterruptEnabled bool - - InterruptChan chan bool - - TxChan chan byte -} - -func NewAcia6551(interruptChan chan bool) *Acia6551 { - acia := &Acia6551{InterruptChan: interruptChan} - acia.Reset() - - return acia -} - -func (a *Acia6551) Reset() { - a.TxChan = make(chan byte, 4096) - - a.tx = 0 - a.txEmpty = true - - a.rx = 0 - a.rxFull = false - - a.lastTxWrite = 0 - a.lastRxRead = 0 - a.overrun = false - - a.rxInterruptEnabled = false - a.txInterruptEnabled = false -} - -func (a *Acia6551) Size() int { - return 4 -} - -func (a *Acia6551) Read(address uint16) byte { - switch address { - case aciaData: - return a.rxRead() - case aciaStatus: - return a.statusRegister() - case aciaCommand: - return a.commandRegister - case aciaControl: - return a.controlRegister - default: - panic(fmt.Errorf("ACIA 6551 cannot handle addressing 0x%04X", address)) - } -} - -func (a *Acia6551) rxRead() byte { - a.lastRxRead = unixTime() - a.overrun = false - a.rxFull = false - return a.rx -} - -func (a *Acia6551) RxWrite(data byte) { - // Oh noes! - if a.rxFull { - a.overrun = true - } - - a.rx = data - a.rxFull = true - - if a.rxInterruptEnabled { - a.InterruptChan <- true - } -} - -func (a *Acia6551) statusRegister() byte { - now := unixTime() - status := byte(0) - - if a.rxFull && (now >= (a.lastRxRead + a.baudRateDelay)) { - status |= 0x08 - } - - if a.txEmpty && (now >= (a.lastTxWrite + a.baudRateDelay)) { - status |= 0x10 - } - - if a.overrun { - status |= 0x04 - } - - return status -} - -func (a *Acia6551) Write(address uint16, value byte) { - switch address { - case aciaData: - a.txWrite(value) - case aciaStatus: - a.Reset() - case aciaCommand: - a.setCommandRegister(value) - case aciaControl: - a.setControlRegister(value) - default: - panic(fmt.Errorf("ACIA 6551 cannot handle addressing 0x%04X", address)) - } -} - -func (a *Acia6551) txWrite(value byte) { - a.lastTxWrite = unixTime() - a.tx = value - a.txEmpty = false - - // Post for others - a.debugTxOutput() -} - -func (a *Acia6551) TxRead() byte { - a.txEmpty = true - - if a.txInterruptEnabled { - a.InterruptChan <- true - } - - return a.tx -} - -func (a *Acia6551) HasTx() bool { - return !a.txEmpty -} - -func (a *Acia6551) HasRx() bool { - return a.rxFull -} - -func (a *Acia6551) debugTxOutput() { - if a.HasTx() { - a.TxChan <- a.TxRead() - } -} - -func (a *Acia6551) setCommandRegister(data byte) { - fmt.Printf("Setting Acia6551 Command Register: %02X\n", data) - - a.commandRegister = data - - a.rxInterruptEnabled = ((data >> 1) & 1) == 0 - a.txInterruptEnabled = ((data>>2)&1) == 1 && ((data>>3)&1) == 0 - - fmt.Printf("RxIRQ: %t; TxIRQ: %t\n", a.rxInterruptEnabled, a.txInterruptEnabled) -} - -func (a *Acia6551) setControlRegister(data byte) { - a.controlRegister = data - - if data == 0x00 { - a.Reset() - } else { - a.setBaudRate(baudRateSelectors[data&0x0f]) - } -} - -func (a *Acia6551) setBaudRate(baudRate int) { - fmt.Printf("Setting baudrate at %d\n", baudRate) - - a.baudRate = baudRate - - // Set baudRateDelay in nanoseconds. It's an approximation. - if baudRate > 0 { - a.baudRateDelay = int64((1.0 / float64(baudRate)) * 1000000000 * 8) - } else { - a.baudRateDelay = 0 - } -} - -func unixTime() int64 { - return time.Now().UnixNano() -} diff --git a/devices/via6522.go b/devices/via6522.go deleted file mode 100644 index 3b4b20d..0000000 --- a/devices/via6522.go +++ /dev/null @@ -1,21 +0,0 @@ -package devices - -type Via6522 struct { -} - -func (v *Via6522) Size() int { - return 0x10 -} - -func (v *Via6522) Read(address uint16) byte { - return 0x00 -} - -func (v *Via6522) Write(address uint16, data byte) { - // NOP -} - -func NewVia6522(interruptChan chan bool) *Via6522 { - via := &Via6522{} - return via -} diff --git a/home.html b/home.html deleted file mode 100644 index 0537907..0000000 --- a/home.html +++ /dev/null @@ -1,99 +0,0 @@ - - - -i6502 Serial Terminal - - - - - - -
-
- - -
- - diff --git a/i6502.go.old b/i6502.go.old deleted file mode 100644 index e6a90d3..0000000 --- a/i6502.go.old +++ /dev/null @@ -1,75 +0,0 @@ -/* -i6502 is a software emulator of my i6502 home-built computer. It uses -the 65C02 microprocessor, 32kB RAM and 16kB ROM. -*/ -package main - -import ( - "fmt" - "github.com/ariejan/i6502/bus" - "github.com/ariejan/i6502/cpu" - "github.com/ariejan/i6502/devices" - "github.com/ariejan/i6502/memory" - "os" - "os/signal" -) - -func main() { - os.Exit(mainReturningStatus()) -} - -func mainReturningStatus() int { - // 32kB RAM - ram := memory.CreateRam() - - // 16kB ROM, filled from file - rom, err := memory.LoadRomFromFile("rom/ehbasic.rom") - if err != nil { - panic(err) - } - - acia6551 := devices.NewAcia6551() - - // 16-bit address bus - bus, _ := bus.CreateBus() - bus.Attach(ram, "32kB RAM", 0x0000) - bus.Attach(rom, "16kB ROM", 0xC000) - bus.Attach(acia6551, "ACIA 6551", 0x8800) - - fmt.Println(bus) - - exitChan := make(chan int, 0) - - cpu := &cpu.Cpu{Bus: bus, ExitChan: exitChan} - cpu.Reset() - - go serialServer(cpu, acia6551) - - go func() { - for { - cpu.Step() - } - }() - - var ( - sig os.Signal - exitStatus int - ) - - sigChan := make(chan os.Signal, 1) - signal.Notify(sigChan, os.Interrupt) - - select { - case exitStatus = <-exitChan: - // Okay, handle the rest of the code - case sig = <-sigChan: - fmt.Println("\nGot signal: ", sig) - exitStatus = 1 - } - - fmt.Println(cpu) - fmt.Println("Dumping RAM into `core` file") - ram.Dump("core") - - return exitStatus -} diff --git a/intcore b/intcore deleted file mode 100644 index d993fb1..0000000 Binary files a/intcore and /dev/null differ diff --git a/machine.go b/machine.go deleted file mode 100644 index 2931378..0000000 --- a/machine.go +++ /dev/null @@ -1,93 +0,0 @@ -package main - -import ( - "github.com/ariejan/i6502/bus" - "github.com/ariejan/i6502/cpu" - "github.com/ariejan/i6502/devices" - "github.com/ariejan/i6502/memory" - "os" -) - -type Machine struct { - // Outgoing bytes, using the serial interface - SerialTx chan byte - - // Incoming bytes, using the serial interface - SerialRx chan byte - - // The cpu, bus etc. - cpu *cpu.Cpu - bus *bus.Bus -} - -// Creates a new i6502 Machine instance -func CreateMachine() *Machine { - // Channel for handling interrupts - irqChan := make(chan bool, 0) - nmiChan := make(chan bool, 0) - - ram := memory.CreateRam() - - rom, err := memory.LoadRomFromFile("rom/ehbasic.rom") - if err != nil { - panic(err) - } - - acia6551 := devices.NewAcia6551(irqChan) - via6522 := devices.NewVia6522(irqChan) - - bus, _ := bus.CreateBus() - bus.Attach(ram, "32kB RAM", 0x0000) - bus.Attach(rom, "16kB ROM", 0xC000) - bus.Attach(via6522, "VIA 6522 Parallel", 0x8000) - bus.Attach(acia6551, "ACIA 6551 Serial", 0x8800) - - cpu := &cpu.Cpu{Bus: bus, IrqChan: irqChan, NmiChan: nmiChan, ExitChan: make(chan int, 0)} - - machine := &Machine{SerialTx: make(chan byte, 256), SerialRx: make(chan byte, 256), cpu: cpu, bus: bus} - - // Run the CPU - go func() { - for { - cpu.Step() - } - }() - - // Connect acia6551 Tx to SerialTx - go func() { - for { - select { - case data := <-acia6551.TxChan: - machine.SerialTx <- data - } - } - }() - - // Connect SerialRx to acia6551 Rx - go func() { - for { - select { - case data := <-machine.SerialRx: - acia6551.RxWrite(data) - } - } - }() - - go func() { - for { - select { - case <-machine.cpu.ExitChan: - ram.Dump("intcore") - os.Exit(42) - } - } - }() - - cpu.Reset() - - return machine -} - -func (m *Machine) Reset() { - m.cpu.Reset() -} diff --git a/main b/main deleted file mode 100755 index 8339b8c..0000000 Binary files a/main and /dev/null differ diff --git a/main.go b/main.go deleted file mode 100644 index 1e41695..0000000 --- a/main.go +++ /dev/null @@ -1,40 +0,0 @@ -package main - -import ( - "flag" - "log" - "net/http" - "text/template" -) - -var ( - addr = flag.String("addr", ":6123", "http service address") - homeTmpl = template.Must(template.ParseFiles("home.html")) -) - -func serveHome(w http.ResponseWriter, r *http.Request) { - if r.URL.Path != "/" { - http.Error(w, "Not found", 404) - return - } - - if r.Method != "GET" { - http.Error(w, "Method not allowed", 405) - return - } - - w.Header().Set("Content-Type", "text/html; charset=utf-8") - homeTmpl.Execute(w, r.Host) -} - -func main() { - flag.Parse() - - http.HandleFunc("/", serveHome) - http.HandleFunc("/ws", serveWs) - - err := http.ListenAndServe(*addr, nil) - if err != nil { - log.Fatal("ListenAndServe: ", err) - } -} diff --git a/memory/memory.go b/memory/memory.go deleted file mode 100644 index 8cb94c2..0000000 --- a/memory/memory.go +++ /dev/null @@ -1,9 +0,0 @@ -// Package memory provides different memory components -// and a common interface. -package memory - -type Memory interface { - Size() int - Read(address uint16) byte - Write(address uint16, value byte) -} diff --git a/memory/ram.go b/memory/ram.go deleted file mode 100644 index a1c3737..0000000 --- a/memory/ram.go +++ /dev/null @@ -1,33 +0,0 @@ -package memory - -import ( - "io/ioutil" -) - -// Ram provides 32kB of Random Access Memory -type Ram struct { - data [0x8000]byte -} - -func (ram *Ram) Size() int { - return len(ram.data) -} - -func (ram *Ram) Read(address uint16) byte { - return ram.data[address] -} - -func (ram *Ram) Write(address uint16, value byte) { - ram.data[address] = value -} - -func CreateRam() *Ram { - return &Ram{} -} - -func (ram *Ram) Dump(path string) { - err := ioutil.WriteFile(path, ram.data[:], 0640) - if err != nil { - panic(err) - } -} diff --git a/memory/rom.go b/memory/rom.go deleted file mode 100644 index 800f3d7..0000000 --- a/memory/rom.go +++ /dev/null @@ -1,42 +0,0 @@ -package memory - -import ( - "io/ioutil" -) - -// Rom provies 16kB of Read Only Memory, typcially loaded from file. -type Rom struct { - data [0x4000]byte -} - -func (rom *Rom) Size() int { - return len(rom.data) -} - -func (rom *Rom) Read(address uint16) byte { - return rom.data[address] -} - -func (rom *Rom) Write(address uint16, value byte) { - panic("Cannot write to ROM!") -} - -// Load ROM from a binary file. The data is placed -// at the beginning of ROM. -func LoadRomFromFile(path string) (*Rom, error) { - // Read data from file - data, err := ioutil.ReadFile(path) - if err != nil { - return nil, err - } - - // Create the rom instance - rom := &Rom{} - - // Load data into ROM - for i, b := range data { - rom.data[i] = b - } - - return rom, nil -} diff --git a/rom/test.rom b/rom/test.rom deleted file mode 120000 index f7a0f95..0000000 --- a/rom/test.rom +++ /dev/null @@ -1 +0,0 @@ -../../asm/build/kernal.rom \ No newline at end of file diff --git a/server.go.old b/server.go.old deleted file mode 100644 index e14d5af..0000000 --- a/server.go.old +++ /dev/null @@ -1,60 +0,0 @@ -package main - -import ( - "bufio" - "fmt" - "github.com/ariejan/i6502/cpu" - "github.com/ariejan/i6502/devices" - "net" -) - -func handleConnection(c net.Conn, cpu *cpu.Cpu, acia *devices.Acia6551) { - - // Force telnet into character mode - c.Write([]byte("\377\375\042\377\373\001")) - c.Write([]byte("-- i6502 Serial Terminal --\n")) - - // Transfer output to the client - go func() { - for { - select { - case data := <-acia.TxChan: - c.Write([]byte{data}) - } - } - }() - - go func() { - reader := bufio.NewReader(c) - - for { - b, err := reader.ReadByte() - if err != nil { - panic(err) - } - - // Push to CPU - acia.RxChan <- b - } - }() - - fmt.Println("Client connected. Resetting CPU.") - cpu.Reset() -} - -func serialServer(cpu *cpu.Cpu, acia *devices.Acia6551) { - listen, err := net.Listen("tcp", ":6000") - if err != nil { - panic(err) - } - - for { - conn, err := listen.Accept() - defer conn.Close() - - if err != nil { - continue - } - go handleConnection(conn, cpu, acia) - } -}