From dd372c8a2d3dda6799da6e4912f602fcf750fcb9 Mon Sep 17 00:00:00 2001 From: Takashi Toyoshima Date: Fri, 5 Dec 2014 02:43:58 +0900 Subject: [PATCH] Ready to implement a 6502 interpreter All investigation for implementation and testing were done. Now, 6502.S can be verified on qemu-arm, and run even on LPC1114. All I have to do is just implement the 6502 interpreter. --- 6502.S | 1027 +++++++++++++++++++++++++++++++++++++++++++++++++ Makefile | 52 +++ apple2.S | 115 ++++++ lpc1114.ld | 37 ++ registers.inc | 94 +++++ reset.S | 32 ++ test.c | 34 ++ uart.S | 153 ++++++++ vectors.S | 97 +++++ 9 files changed, 1641 insertions(+) create mode 100644 6502.S create mode 100644 Makefile create mode 100644 apple2.S create mode 100644 lpc1114.ld create mode 100644 registers.inc create mode 100644 reset.S create mode 100644 test.c create mode 100644 uart.S create mode 100644 vectors.S diff --git a/6502.S b/6502.S new file mode 100644 index 0000000..e70b107 --- /dev/null +++ b/6502.S @@ -0,0 +1,1027 @@ + .syntax unified + .cpu cortex-m0 + .align 2 + .thumb + .thumb_func + .text + + .extern cpu6502_dump + .extern cpu6502_load + .extern cpu6502_store + +#define T0 r4 +#define T1 r5 +#define PC r6 +#define SR r7 +#define RA r8 +#define RX r9 +#define RY r10 +#define SP r11 + +#define FLAG_N (1 << 7) +#define FLAG_V (1 << 6) +#define FLAG_D (1 << 3) +#define FLAG_I (1 << 2) +#define FLAG_Z (1 << 1) +#define FLAG_C (1 << 0) + +.macro _ldb + bl cpu6502_load +.endm + +.macro _ldw + mov T0, r0 + bl cpu6502_load + mov T1, r0 + adds r0, T0, #1 + bl cpu6502_load + lsls r0, r0, #8 + adds r0, r0, T1 +.endm + +.macro _stb + bl cpu6502_store +.endm + +.macro _stw + mov T0, r0 + mov T1, r1 + bl cpu6502_store + adds r0, T0, #1 + lsrs r1, T1, #8 + bl cpu6502_store +.endm + +.macro _push16 reg + mov r0, SP + mov r1, \reg + lsrs r1, r1, #8 + _stb + mov r0, SP + subs r0, r0, #1 + mov r1, \reg + _stb + mov r0, SP + subs r0, r0, #2 + mov SP, r0 +.endm + +.macro _decode + b decode +.endm + +.macro _fromImm8 + adds PC, PC, #1 + mov r0, PC + _ldb +.endm + +.macro _clx flag + movs T0, #\flag + bics SR, SR, T0 + adds PC, PC, #1 +.endm + +.macro _sex flag + movs T0, #\flag + orrs SR, SR, T0 + adds PC, PC, #1 +.endm + +.macro _ld reg + _clx (FLAG_N | FLAG_Z) + mov \reg, r0 + beq 1f + _sex FLAG_Z +1: + movs r1, #0x80 + tst r0, r1 + beq 1f + _sex FLAG_N +1: + adds PC, PC, #1 +.endm + +.macro _resume + ldr r0, =#r_pc + ldr PC, [r0] + ldr r0, =#r_sr + ldr SR, [r0] + ldr r0, =#r_a + ldr T0, [r0] + mov RA, T0 + ldr r0, =#r_x + ldr T0, [r0] + mov RX, T0 + ldr r0, =#r_y + ldr T0, [r0] + mov RY, T0 + ldr r0, =#r_sp + ldr T0, [r0] + mov SP, T0 + ldr T0, =#op_table +.endm + +.macro _suspend + ldr r0, =#r_pc + str PC, [r0] + ldr r0, =#r_sr + str SR, [r0] + ldr r0, =#r_a + mov T0, RA + str T0, [r0] + ldr r0, =#r_x + mov T0, RX + str T0, [r0] + ldr r0, =#r_y + mov T0, RY + str T0, [r0] + ldr r0, =#r_sp + mov T0, SP + str T0, [r0] +.endm + +op00: + b quit +op01: + b quit +op02: + b quit +op03: + b quit +op04: + b quit +op05: + b quit +op06: + b quit +op07: + b quit +op08: + b quit +op09: + b quit +op0a: + b quit +op0b: + b quit +op0c: + b quit +op0d: + b quit +op0e: + b quit +op0f: + b quit +op10: + b quit +op11: + b quit +op12: + b quit +op13: + b quit +op14: + b quit +op15: + b quit +op16: + b quit +op17: + b quit +op18: // CLC + _clx FLAG_C + _decode +op19: + b quit +op1a: + b quit +op1b: + b quit +op1c: + b quit +op1d: + b quit +op1e: + b quit +op1f: + b quit +op20: // JSR + adds T0, PC, #2 + _push16 T0 + adds r0, PC, #1 + _ldw + mov PC, r0 + _decode +op21: + b quit +op22: + b quit +op23: + b quit +op24: + b quit +op25: + b quit +op26: + b quit +op27: + b quit +op28: + b quit +op29: + b quit +op2a: + b quit +op2b: + b quit +op2c: + b quit +op2d: + b quit +op2e: + b quit +op2f: + b quit +op30: + b quit +op31: + b quit +op32: + b quit +op33: + b quit +op34: + b quit +op35: + b quit +op36: + b quit +op37: + b quit +op38: // SEC + _sex FLAG_C + _decode +op39: + b quit +op3a: + b quit +op3b: + b quit +op3c: + b quit +op3d: + b quit +op3e: + b quit +op3f: + b quit +op40: + b quit +op41: + b quit +op42: + b quit +op43: + b quit +op44: + b quit +op45: + b quit +op46: + b quit +op47: + b quit +op48: + b quit +op49: + b quit +op4a: + b quit +op4b: + b quit +op4c: + b quit +op4d: + b quit +op4e: + b quit +op4f: + b quit +op50: + b quit +op51: + b quit +op52: + b quit +op53: + b quit +op54: + b quit +op55: + b quit +op56: + b quit +op57: + b quit +op58: // CLI + _clx FLAG_I + _decode +op59: + b quit +op5a: + b quit +op5b: + b quit +op5c: + b quit +op5d: + b quit +op5e: + b quit +op5f: + b quit +op60: + b quit +op61: + b quit +op62: + b quit +op63: + b quit +op64: + b quit +op65: + b quit +op66: + b quit +op67: + b quit +op68: + b quit +op69: + b quit +op6a: + b quit +op6b: + b quit +op6c: + b quit +op6d: + b quit +op6e: + b quit +op6f: + b quit +op70: + b quit +op71: + b quit +op72: + b quit +op73: + b quit +op74: + b quit +op75: + b quit +op76: + b quit +op77: + b quit +op78: // SEI + _sex FLAG_I + _decode +op79: + b quit +op7a: + b quit +op7b: + b quit +op7c: + b quit +op7d: + b quit +op7e: + b quit +op7f: + b quit +op80: + b quit +op81: + b quit +op82: + b quit +op83: + b quit +op84: + b quit +op85: + b quit +op86: + b quit +op87: + b quit +op88: + b quit +op89: + b quit +op8a: + b quit +op8b: + b quit +op8c: + b quit +op8d: + b quit +op8e: + b quit +op8f: + b quit +op90: + b quit +op91: + b quit +op92: + b quit +op93: + b quit +op94: + b quit +op95: + b quit +op96: + b quit +op97: + b quit +op98: + b quit +op99: + b quit +op9a: + b quit +op9b: + b quit +op9c: + b quit +op9d: + b quit +op9e: + b quit +op9f: + b quit +opa0: // LDY - Immediate + _fromImm8 + _ld RY + _decode +opa1: + b quit +opa2: // LDX - Immediate + _fromImm8 + _ld RX + _decode +opa3: + b quit +opa4: + b quit +opa5: + b quit +opa6: + b quit +opa7: + b quit +opa8: + b quit +opa9: // LDA - Immediate + _fromImm8 + _ld RA + _decode +opaa: + b quit +opab: + b quit +opac: + b quit +opad: + b quit +opae: + b quit +opaf: + b quit +opb0: + b quit +opb1: + b quit +opb2: + b quit +opb3: + b quit +opb4: + b quit +opb5: + b quit +opb6: + b quit +opb7: + b quit +opb8: // CLV + _clx FLAG_V + _decode +opb9: + b quit +opba: + b quit +opbb: + b quit +opbc: + b quit +opbd: + b quit +opbe: + b quit +opbf: + b quit +opc0: + b quit +opc1: + b quit +opc2: + b quit +opc3: + b quit +opc4: + b quit +opc5: + b quit +opc6: + b quit +opc7: + b quit +opc8: + b quit +opc9: + b quit +opca: + b quit +opcb: + b quit +opcc: + b quit +opcd: + b quit +opce: + b quit +opcf: + b quit +opd0: + b quit +opd1: + b quit +opd2: + b quit +opd3: + b quit +opd4: + b quit +opd5: + b quit +opd6: + b quit +opd7: + b quit +opd8: // CLD + _clx FLAG_D + _decode +opd9: + b quit +opda: + b quit +opdb: + b quit +opdc: + b quit +opdd: + b quit +opde: + b quit +opdf: + b quit +ope0: + b quit +ope1: + b quit +ope2: + b quit +ope3: + b quit +ope4: + b quit +ope5: + b quit +ope6: + b quit +ope7: + b quit +ope8: + b quit +ope9: + b quit +opea: + b quit +opeb: + b quit +opec: + b quit +oped: + b quit +opee: + b quit +opef: + b quit +opf0: + b quit +opf1: + b quit +opf2: + b quit +opf3: + b quit +opf4: + b quit +opf5: + b quit +opf6: + b quit +opf7: + b quit +opf8: // SED + _sex FLAG_D + _decode +opf9: + b quit +opfa: + b quit +opfb: + b quit +opfc: + b quit +opfd: + b quit +opfe: + b quit +opff: + b quit + + .global cpu6502_reset + .type cpu6502_reset, %function +cpu6502_reset: + push {r4-r7,lr} + movs r4, #0x00 + movs r5, #0x01 + lsls r5, r5, #8 + adds r5, r5, #0xff + movs r6, #0x30 + ldr r7, =#r_a + str r4, [r7] + ldr r7, =#r_x + str r4, [r7] + ldr r7, =#r_y + str r4, [r7] + ldr r7, =#r_sp + str r5, [r7] + ldr r7, =#r_sr + str r6, [r7] + ldr r0, =#0xfffc + _ldw + ldr r7, =#r_pc + str r0, [r7] + pop {r4-r7,pc} + + .global cpu6502_run + .type cpu6502_run, %function +cpu6502_run: + push {r4-r7,lr} + mov r0, r8 + mov r1, r9 + mov r2, r10 + mov r3, r11 + mov r4, r12 + push {r0-r4} + _resume + _decode +quit: + mov r12, r0 + _suspend + pop {r0-r4} + mov r8, r0 + mov r9, r1 + mov r10, r2 + mov r11, r3 + mov r0, r12 + mov r12, r4 + pop {r4-r7,pc} + +// void dump(uint16_t pc); + .type dump, %function +dump: + push {lr} + _suspend + ldr r0, =#r_sp + ldr r1, [r0] + ldr r0, =#r_sr + ldr r2, [r0] + push {r1,r2} + ldr r3, =#r_pc + ldr r0, [r3] + ldr r3, =#r_a + ldr r1, [r3] + ldr r3, =#r_x + ldr r2, [r3] + ldr r3, =#r_y + ldr r3, [r3] + // r0=pc, r1=a, r2=x, r3=y, [sp]=sp, [sp+4]=sr + bl cpu6502_dump + mov r0, sp + adds r0, r0, #8 + mov sp, r0 + pop {pc} + +// void decode(); + .type decode, %function +decode: + bl dump + mov r0, PC + _ldb + lsls r1, r0, #2 + ldr r2, =#op_table + adds r3, r2, r1 + ldr r1, [r3] + mov pc, r1 + + .section .rodata +op_table: + .long op00 + .long op01 + .long op02 + .long op03 + .long op04 + .long op05 + .long op06 + .long op07 + .long op08 + .long op09 + .long op0a + .long op0b + .long op0c + .long op0d + .long op0e + .long op0f + .long op10 + .long op11 + .long op12 + .long op13 + .long op14 + .long op15 + .long op16 + .long op17 + .long op18 + .long op19 + .long op1a + .long op1b + .long op1c + .long op1d + .long op1e + .long op1f + .long op20 + .long op21 + .long op22 + .long op23 + .long op24 + .long op25 + .long op26 + .long op27 + .long op28 + .long op29 + .long op2a + .long op2b + .long op2c + .long op2d + .long op2e + .long op2f + .long op30 + .long op31 + .long op32 + .long op33 + .long op34 + .long op35 + .long op36 + .long op37 + .long op38 + .long op39 + .long op3a + .long op3b + .long op3c + .long op3d + .long op3e + .long op3f + .long op40 + .long op41 + .long op42 + .long op43 + .long op44 + .long op45 + .long op46 + .long op47 + .long op48 + .long op49 + .long op4a + .long op4b + .long op4c + .long op4d + .long op4e + .long op4f + .long op50 + .long op51 + .long op52 + .long op53 + .long op54 + .long op55 + .long op56 + .long op57 + .long op58 + .long op59 + .long op5a + .long op5b + .long op5c + .long op5d + .long op5e + .long op5f + .long op60 + .long op61 + .long op62 + .long op63 + .long op64 + .long op65 + .long op66 + .long op67 + .long op68 + .long op69 + .long op6a + .long op6b + .long op6c + .long op6d + .long op6e + .long op6f + .long op70 + .long op71 + .long op72 + .long op73 + .long op74 + .long op75 + .long op76 + .long op77 + .long op78 + .long op79 + .long op7a + .long op7b + .long op7c + .long op7d + .long op7e + .long op7f + .long op80 + .long op81 + .long op82 + .long op83 + .long op84 + .long op85 + .long op86 + .long op87 + .long op88 + .long op89 + .long op8a + .long op8b + .long op8c + .long op8d + .long op8e + .long op8f + .long op90 + .long op91 + .long op92 + .long op93 + .long op94 + .long op95 + .long op96 + .long op97 + .long op98 + .long op99 + .long op9a + .long op9b + .long op9c + .long op9d + .long op9e + .long op9f + .long opa0 + .long opa1 + .long opa2 + .long opa3 + .long opa4 + .long opa5 + .long opa6 + .long opa7 + .long opa8 + .long opa9 + .long opaa + .long opab + .long opac + .long opad + .long opae + .long opaf + .long opb0 + .long opb1 + .long opb2 + .long opb3 + .long opb4 + .long opb5 + .long opb6 + .long opb7 + .long opb8 + .long opb9 + .long opba + .long opbb + .long opbc + .long opbd + .long opbe + .long opbf + .long opc0 + .long opc1 + .long opc2 + .long opc3 + .long opc4 + .long opc5 + .long opc6 + .long opc7 + .long opc8 + .long opc9 + .long opca + .long opcb + .long opcc + .long opcd + .long opce + .long opcf + .long opd0 + .long opd1 + .long opd2 + .long opd3 + .long opd4 + .long opd5 + .long opd6 + .long opd7 + .long opd8 + .long opd9 + .long opda + .long opdb + .long opdc + .long opdd + .long opde + .long opdf + .long ope0 + .long ope1 + .long ope2 + .long ope3 + .long ope4 + .long ope5 + .long ope6 + .long ope7 + .long ope8 + .long ope9 + .long opea + .long opeb + .long opec + .long oped + .long opee + .long opef + .long opf0 + .long opf1 + .long opf2 + .long opf3 + .long opf4 + .long opf5 + .long opf6 + .long opf7 + .long opf8 + .long opf9 + .long opfa + .long opfb + .long opfc + .long opfd + .long opfe + .long opff + + .bss +r_pc: .long 0 +r_a: .long 0 +r_x: .long 0 +r_y: .long 0 +r_sp: .long 0 +r_sr: .long 0 + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..6a40d07 --- /dev/null +++ b/Makefile @@ -0,0 +1,52 @@ +APP = lpc1114app +CC = arm-linux-gnueabi-gcc +AS = arm-none-eabi-gcc -c +LD = arm-none-eabi-ld +OBJCOPY = arm-none-eabi-objcopy +LDSCRIPT= lpc1114.ld +LPC21ISP= lpc21isp +SERIAL = /dev/ttyUSB0 +#SERIAL = /dev/ttyACM0 +SPEED = 115200 +#SPEED = 9600 +CLOCK = 12000 +ROM = applebasic +ROMOBJ = $(ROM).o +ROMFLAG = -I binary -O elf32-littlearm -B arm --rename-section .data=.rodata +OBJS = vectors.o reset.o 6502.o apple2.o uart.o $(ROMOBJ) + +$(APP).bin: $(APP) + $(OBJCOPY) -O binary $< $@ + +$(APP): $(LDSCRIPT) $(OBJS) + $(LD) -T $(LDSCRIPT) -o $@ $(OBJS) + +$(ROM).rom: + @echo "*********************************************" + @echo "* $(ROM).rom is needed to build the app *" + @echo "*********************************************" + @exit 1 + +%.o: %.S + $(AS) -o $@ $< + +%.o: %.rom + $(OBJCOPY) $(ROMFLAG) $< $@ \ + --redefine-sym _binary_$(ROM)_rom_start=basic_rom \ + --strip-symbol _binary_$(ROM)_rom_end \ + --strip-symbol _binary_$(ROM)_rom_size + +# Test binary that runs on qemu user mode emulation for testing +test: 6502.o test.c + $(CC) -mthumb -static test.c 6502.o -o test && qemu-arm test + +# Assume a CQ Mary comaptible board. +run: $(APP).bin + $(LPC21ISP) -control -term -bin $(APP).bin $(SERIAL) $(SPEED) $(CLOCK) + +clean: + rm -rf $(APP).bin $(APP) $(OBJS) test + +# Use this build target to install required packages if you are on Ubuntu14.04. +install-deps: + sudo apt-get install binutils-arm-none-eabi gcc-arm-none-eabi gcc-arm-linux-gnueabi lpc21isp diff --git a/apple2.S b/apple2.S new file mode 100644 index 0000000..3eaf8c9 --- /dev/null +++ b/apple2.S @@ -0,0 +1,115 @@ + .syntax unified + .cpu cortex-m0 + .align 2 + .thumb + .thumb_func + + .extern basic_rom + + .section .rodata +dump0: + .ascii "*** dump *** PC=$\000" +dump1: + .ascii " A=$\000" +dump2: + .ascii " X=$\000" +dump3: + .ascii " Y=$\000" +dump4: + .ascii " SP=$\000" +dump5: + .ascii " NV-B_DIZC=\000" + + .text + .global cpu6502_dump + .type cpu6502_dump, %function +cpu6502_dump: + push {r4-r7, lr} + mov r4, r0 + mov r5, r1 + mov r6, r2 + mov r7, r3 + ldr r0, =#dump0 + bl uart_putstr + mov r0, r4 + bl uart_puthex16 + ldr r0, =#dump1 + bl uart_putstr + mov r0, r5 + bl uart_puthex + ldr r0, =#dump2 + bl uart_putstr + mov r0, r6 + bl uart_puthex + ldr r0, =#dump3 + bl uart_putstr + mov r0, r7 + bl uart_puthex + ldr r0, =#dump4 + bl uart_putstr + ldr r0, [sp, #20] + bl uart_puthex + ldr r0, =#dump5 + bl uart_putstr + ldr r4, [sp, #24] + mov r0, r4 + lsrs r0, #7 + bl uart_putx + mov r0, r4 + movs r5, #1 + lsrs r0, #6 + ands r0, r5 + bl uart_putx + movs r0, #'-' + bl uart_putc + mov r0, r4 + lsrs r0, #4 + ands r0, r5 + bl uart_putx + movs r0, #'_' + bl uart_putc + mov r0, r4 + lsrs r0, #3 + ands r0, r5 + bl uart_putx + mov r0, r4 + lsrs r0, #2 + ands r0, r5 + bl uart_putx + mov r0, r4 + lsrs r0, #1 + ands r0, r5 + bl uart_putx + mov r0, r4 + ands r0, r5 + bl uart_putx + movs r0, #'\n' + bl uart_putc + pop {r4-r7, pc} + + .global cpu6502_load + .type cpu6502_load, %function +cpu6502_load: + movs r1, r0 + lsrs r0, #8 + movs r2, #0xd0 + cmps r0, r2 + bhs 1f + // TODO: Load from RAM + movs r0, #0 + mov pc, lr +1: + // Load from ROM (0xd000-0xffff) + lsls r2, #8 + subs r1, r1, r2 + ldr r0, =#basic_rom + adds r0, r0, r1 + ldrb r0, [r0] + mov pc, lr + + .global cpu6502_store + .type cpu6502_store, %function +cpu6502_store: + // TODO + mov pc, lr + diff --git a/lpc1114.ld b/lpc1114.ld new file mode 100644 index 0000000..8bce077 --- /dev/null +++ b/lpc1114.ld @@ -0,0 +1,37 @@ +MEMORY +{ + flash (rx) : ORIGIN = 0x00000000, LENGTH = 32K + sram (rwx) : ORIGIN = 0x10000000, LENGTH = 4K +} + +SECTIONS +{ + .text : ALIGN(4) { + _vector_start = .; + KEEP(*(.isr_vector)) + _vector_end = .; + + _text_start = .; + KEEP(*(.text)) + _text_end = .; + + _rodata_start = .; + KEEP(*(.rodata)) + _rodata_end = .; + } > flash + + .data : ALIGN(4) { + _data_start = .; + KEEP(*(.data)) + _data_end = .; + } > sram AT > flash + + .bss : ALIGN(4) { + _bss_start = .; + KEEP(*(.bss)) + _bss_end = .; + } > sram + + _stack_top = 0x10001000; +} + diff --git a/registers.inc b/registers.inc new file mode 100644 index 0000000..fa4705a --- /dev/null +++ b/registers.inc @@ -0,0 +1,94 @@ + .equ U0RBR, 0x40008000 + .equ U0THR, 0x40008000 + .equ U0DLL, 0x40008000 + .equ U0DLM, 0x40008004 + .equ U0IER, 0x40008004 + .equ U0IIR, 0x40008008 + .equ U0FCR, 0x40008008 + .equ FIFO_ENABLE, (1 << 0) + .equ RX_RESET, (1 << 1) + .equ TX_RESET, (1 << 2) + .equ U0LCR, 0x4000800c + .equ WORD_LEN_5, 0 + .equ WORD_LEN_6, 1 + .equ WORD_LEN_7, 2 + .equ WORD_LEN_8, 3 + .equ STOP_BIT_1, (0 << 2) + .equ STOP_BIT_2, (1 << 2) + .equ PARITY_DISABLE,(0 << 3) + .equ PARITY_ENABLE, (1 << 3) + .equ PARITY_EVEN, (0 << 4) + .equ PARITY_ODD, (1 << 4) + .equ PARITY_1, (2 << 4) + .equ PARITY_0, (3 << 4) + .equ BREAK_DISABLE, (0 << 6) + .equ BREAK_ENABLE, (1 << 6) + .equ DLAB_DISABLE, (0 << 7) + .equ DLAB_ENABLE, (1 << 7) + .equ U0MCR, 0x40008010 + .equ U0LSR, 0x40008014 + .equ LSR_THRE, (1 << 5) + .equ U0MSR, 0x40008018 + .equ U0SCR, 0x4000801c + .equ U0ACR, 0x40008020 + .equ U0FDR, 0x40008028 + .equ MULVAL_SHIFT, 4 + .equ U0TER, 0x40008030 + .equ TXEN, (1 << 7) + .equ U0RS485CTRL, 0x4000804c + .equ U0ADRMATCH, 0x40008050 + .equ U0RS485DLY, 0x40008054 + + .equ IOCON_PIO2_0, 0x40044008 + .equ FUNC_PIO, 0 + .equ FUNC_DTR, 1 + .equ FUNC_SSEL, 2 + .equ MODE_DOWN, (1 << 3) + .equ MODE_UP, (2 << 3) + .equ MODE_REP, (3 << 3) + .equ HYS_EN, (1 << 5) + .equ PIO_BASE, (3 << 6) + .equ PIO_MASK, 0x3f + .equ IOCON_PIO1_5, 0x400440a0 + .equ FUNC_RTS, 1 + .equ FUNC_CT32, 2 + .equ IOCON_PIO1_6, 0x400440a4 + .equ FUNC_RXD, 1 + .equ IOCON_PIO1_7, 0x400440a8 + .equ FUNC_TXD, 1 + + .equ SYSAHBCLKCTRL, 0x40048080 + .equ CLK_IOCON, (1 << 16) + .equ CLK_UART, (1 << 12) + + .equ UARTCLKDIV, 0x40048098 + + .equ GPIO0DATA, 0x50003ffc + .equ GPIO0DIR, 0x50008000 + .equ GPIO0IS, 0x50008004 + .equ GPIO0IBE, 0x50008008 + .equ GPIO0IEV, 0x5000800c + .equ GPIO0IE, 0x50008010 + .equ GPIO0RIS, 0x50008014 + .equ GPIO0MIS, 0x50008018 + .equ GPIO0IC, 0x5000801c + + .equ GPIO1DATA, 0x50013ffc + .equ GPIO1DIR, 0x50018000 + .equ GPIO1IS, 0x50018004 + .equ GPIO1IBE, 0x50018008 + .equ GPIO1IEV, 0x5001800c + .equ GPIO1IE, 0x50018010 + .equ GPIO1RIS, 0x50018014 + .equ GPIO1MIS, 0x50018018 + .equ GPIO1IC, 0x5001801c + + .equ GPIO2DATA, 0x50023ffc + .equ GPIO2DIR, 0x50028000 + .equ GPIO2IS, 0x50028004 + .equ GPIO2IBE, 0x50028008 + .equ GPIO2IEV, 0x5002800c + .equ GPIO2IE, 0x50028010 + .equ GPIO2RIS, 0x50028014 + .equ GPIO2MIS, 0x50028018 + .equ GPIO2IC, 0x5002801c diff --git a/reset.S b/reset.S new file mode 100644 index 0000000..a30551f --- /dev/null +++ b/reset.S @@ -0,0 +1,32 @@ + .syntax unified + .cpu cortex-m0 + .align 2 + .thumb + .thumb_func + + .include "registers.inc" + + .extern cpu6502_reset + .extern cpu6502_run + .extern uart_init + .extern uart_putc + + .section .rodata +hello: + .ascii "Applerm II\n\000" + + .text + .global _reset + .type _reset, %function +_reset: + ldr r0, =#(_stack_top - 32) + mov sp, r0 + bl uart_init + ldr r0, =#hello + bl uart_putstr + + bl cpu6502_reset + bl cpu6502_run +1: + b 1b + .size _reset, .-_reset diff --git a/test.c b/test.c new file mode 100644 index 0000000..a88e64b --- /dev/null +++ b/test.c @@ -0,0 +1,34 @@ +#include +#include +#include + +uint8_t mem[0x10000]; + +void cpu6502_dump( + uint16_t pc, uint8_t a, uint8_t x, uint8_t y, uint8_t sp, uint8_t sr) { + printf("*** dump *** PC=$%04x A=$%02x X=$%02x Y=$%02x SP=$%02x " + "NV-B_DIZC=%d%d-%d_%d%d%d%d\n", + pc, a, x, y, sp, (sr >> 7) & 1, (sr >> 6) & 1, (sr >> 4) & 1, + (sr >> 3) & 1, (sr >> 2) & 1, (sr >> 1) & 1, sr & 1); +} + +uint8_t cpu6502_load(uint16_t addr) { + printf("load $%04x => $%02x\n", addr, mem[addr]); + return mem[addr]; +} + +void cpu6502_store(uint16_t addr, uint8_t data) { + printf("store $%04x <= $%02x\n", addr, data); + mem[addr] = data; +} + +int main(int argc, char** argv) { + FILE* fp = fopen("applebasic.rom", "rb"); + memset(mem, 0, 0x10000); + fread(&mem[0xd000], 1, 0x3000, fp); + fclose(fp); + cpu6502_reset(); + printf("quit: $%04x\n", cpu6502_run()); + return 0; +} + diff --git a/uart.S b/uart.S new file mode 100644 index 0000000..0b73465 --- /dev/null +++ b/uart.S @@ -0,0 +1,153 @@ + .syntax unified + .cpu cortex-m0 + .align 2 + .thumb + .thumb_func + + .include "registers.inc" + + .text + + // void uart_init() + .global uart_init + .type uart_init, %function +uart_init: + // 0) Set to provide I/O clock + ldr r0, =#SYSAHBCLKCTRL + ldr r1, [r0] + ldr r2, =#CLK_IOCON + orrs r1, r1, r2 + str r1, [r0] + // 1) IO port configuration to use UART + ldr r0, =#IOCON_PIO1_6 + movs r1, #(PIO_BASE | FUNC_RXD) + str r1, [r0] + ldr r0, =#IOCON_PIO1_7 + movs r1, #(PIO_BASE | FUNC_TXD) + str r1, [r0] + // 2) Set to provide UART clock + ldr r0, =#SYSAHBCLKCTRL + ldr r1, [r0] + ldr r2, =#CLK_UART + orrs r1, r1, r2 + str r1, [r0] + // 3) Set clock divider to enable UART clock + ldr r0, =#UARTCLKDIV + movs r1, #1 + str r1, [r0] + + // UART_PCLK = 12MHz, BR = 115200 + // DLM=0, DLL=4, DIVADDVAL = 5, MULVAL = 8 + ldr r0, =#U0LCR + movs r1, #DLAB_ENABLE + str r1, [r0] + ldr r0, =#U0DLM + movs r1, #0 + str r1, [r0] + ldr r0, =#U0DLL + movs r1, #4 + str r1, [r0] + ldr r0, =#U0FDR + movs r1, #((8 << MULVAL_SHIFT) | 5) + str r1, [r0] + + // Configure as 8-bit, 1 stop bit, no parity mode + ldr r0, =#U0LCR + movs r1, #(WORD_LEN_8 | STOP_BIT_1) + str r1, [r0] + + // Enable TX + ldr r0, =#U0TER + movs r1, #TXEN + str r1, [r0] + + // Reset FIFO + ldr r0, =#U0FCR + movs r1, #(FIFO_ENABLE | RX_RESET | TX_RESET) + str r1, [r0] + + mov pc, lr + .size uart_init, .-uart_init + + // void uart_putc(char c); + .global uart_putc + .type uart_putc, %function +uart_putc: + ldr r1, =#U0LSR + movs r2, #LSR_THRE +1: + ldr r3, [r1] + ands r3, r2, r3 + beq 1b + ldr r1, =#U0THR + str r0, [r1] + mov pc, lr + .size uart_putc, .-uart_putc + + // void uart_putstr(const char* str); + .global uart_putstr + .type uart_putstr, %function +uart_putstr: + push {r4, lr} + mov r4, r0 +1: + ldrb r0, [r4] + movs r0, r0 + beq 1f + bl uart_putc + movs r0, #1 + adds r4, r4, r0 + b 1b +1: + pop {r4, pc} + .size uart_putstr, .-uart_putstr + + // void uart_putx(char x); + .global uart_putx + .type uart_putx, %function +uart_putx: + push {lr} + movs r1, #10 + cmp r0, r1 + bhs 1f + movs r1, #'0' + adds r0, r0, r1 + bl uart_putc + pop {pc} +1: + movs r1, #('a' - 10) + adds r0, r0, r1 + bl uart_putc + pop {pc} + .size uart_putx, .-uart_putx + + // void uart_puthex(char n); + .global uart_puthex + .type uart_puthex, %function +uart_puthex: + push {lr} + push {r0} + lsrs r0, r0, #4 + bl uart_putx + pop {r0} + movs r1, #0xf + ands r0, r0, r1 + bl uart_putx + pop {pc} + .size uart_puthex, .-uart_puthex + + // void uart_puthex16(short n); + .global uart_puthex16 + .type uart_puthex16, %function +uart_puthex16: + push {lr} + push {r0} + lsrs r0, r0, #8 + bl uart_puthex + pop {r0} + movs r1, #0xff + ands r0, r0, r1 + bl uart_puthex + pop {pc} + .size uart_puthex16, .-uart_puthex16 + diff --git a/vectors.S b/vectors.S new file mode 100644 index 0000000..0658e7b --- /dev/null +++ b/vectors.S @@ -0,0 +1,97 @@ + .syntax unified + .cpu cortex-m0 + .align 2 + .thumb + .thumb_func + + .section .isr_vector + + .long _stack_top // 0x0000 + .long _reset // 0x0004 + .long _nmi // 0x0008 + .long _hard_fault // 0x000c + .long _reserved // 0x0010 + .long _reserved // 0x0014 + .long _reserved // 0x0018 + .long _reserved // 0x001c + .long _reserved // 0x0020 + .long _reserved // 0x0024 + .long _reserved // 0x0028 + .long _svc // 0x002c + .long _reserved // 0x0030 + .long _reserved // 0x0034 + .long _pend_sv // 0x0038 + .long _sys_tick // 0x003c + .long _pio0_0_wakeup // 0x0040 + .long _pio0_1_wakeup // 0x0044 + .long _pio0_2_wakeup // 0x0048 + .long _pio0_3_wakeup // 0x004c + .long _pio0_4_wakeup // 0x0050 + .long _pio0_5_wakeup // 0x0054 + .long _pio0_6_wakeup // 0x0058 + .long _pio0_7_wakeup // 0x005c + .long _pio0_8_wakeup // 0x0060 + .long _pio0_9_wakeup // 0x0064 + .long _pio0_10_wakeup // 0x0068 + .long _pio0_11_wakeup // 0x006c + .long _pio1_0_wakeup // 0x0070 + .long _c_can // 0x0074 + .long _ssp1 // 0x0078 + .long _i2c // 0x007c + .long _ct16b0 // 0x0080 + .long _ct16b1 // 0x0084 + .long _ct32b0 // 0x0088 + .long _ct32b1 // 0x008c + .long _ssp0 // 0x0090 + .long _uart // 0x0094 + .long _reserved // 0x0098 + .long _reserved // 0x009c + .long _adc // 0x00a0 + .long _wdt // 0x00a4 + .long _bod // 0x00a8 + .long _reserved // 0x00ac + .long _int3 // 0x00b0 + .long _int2 // 0x00b4 + .long _int1 // 0x00b8 + .long _int0 // 0x00bc + + .text + +_adc: +_bod: +_c_can: +_ct16b0: +_ct16b1: +_ct32b0: +_ct32b1: +_hard_fault: +_i2c: +_int0: +_int1: +_int2: +_int3: +_nmi: +_pend_sv: +_pio0_0_wakeup: +_pio0_1_wakeup: +_pio0_2_wakeup: +_pio0_3_wakeup: +_pio0_4_wakeup: +_pio0_5_wakeup: +_pio0_6_wakeup: +_pio0_7_wakeup: +_pio0_8_wakeup: +_pio0_9_wakeup: +_pio0_10_wakeup: +_pio0_11_wakeup: +_pio1_0_wakeup: +_reserved: +//_reset: +_ssp0: +_ssp1: +_svc: +_sys_tick: +_uart: +_wdt: +loop: + b loop