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.
This commit is contained in:
Takashi Toyoshima 2014-12-05 02:43:58 +09:00
parent 6b1e8c1914
commit dd372c8a2d
9 changed files with 1641 additions and 0 deletions

1027
6502.S Normal file

File diff suppressed because it is too large Load Diff

52
Makefile Normal file
View File

@ -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

115
apple2.S Normal file
View File

@ -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

37
lpc1114.ld Normal file
View File

@ -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;
}

94
registers.inc Normal file
View File

@ -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

32
reset.S Normal file
View File

@ -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

34
test.c Normal file
View File

@ -0,0 +1,34 @@
#include <stdio.h>
#include <stdint.h>
#include <string.h>
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;
}

153
uart.S Normal file
View File

@ -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

97
vectors.S Normal file
View File

@ -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