diff options
-rw-r--r-- | AppleI_Manual.pdf | bin | 0 -> 1775046 bytes | |||
-rw-r--r-- | ToDo | 4 | ||||
-rw-r--r-- | docs/interpreter.md | 13 | ||||
-rw-r--r-- | headers/apple.h | 15 | ||||
-rw-r--r-- | headers/include.h | 9 | ||||
-rw-r--r-- | makefile | 4 | ||||
-rw-r--r-- | src/apple.h | 39 | ||||
-rw-r--r-- | src/cpu/6502.h (renamed from headers/6502.h) | 36 | ||||
-rw-r--r-- | src/cpu/addressing.h (renamed from headers/addressing.h) | 6 | ||||
-rw-r--r-- | src/cpu/instructions/definitions.h (renamed from headers/instructions/definitions.h) | 0 | ||||
-rw-r--r-- | src/cpu/instructions/illegal/definitions.h (renamed from headers/instructions/illegal/definitions.h) | 0 | ||||
-rw-r--r-- | src/cpu/instructions/illegal/init.h (renamed from headers/instructions/illegal/init.h) | 0 | ||||
-rw-r--r-- | src/cpu/instructions/illegal/table-append.h (renamed from headers/instructions/illegal/table-append.h) | 0 | ||||
-rw-r--r-- | src/cpu/instructions/init.h (renamed from headers/instructions/init.h) | 0 | ||||
-rw-r--r-- | src/cpu/instructions/table.h (renamed from headers/instructions/table.h) | 0 | ||||
-rw-r--r-- | src/debug.h (renamed from headers/debug.h) | 0 | ||||
-rw-r--r-- | src/include.h | 6 | ||||
-rw-r--r-- | src/interpreter.c (renamed from interpreter.c) | 6 | ||||
-rw-r--r-- | test/02-Stack | 57 | ||||
-rw-r--r-- | test/99-WozMon | 260 |
20 files changed, 389 insertions, 66 deletions
diff --git a/AppleI_Manual.pdf b/AppleI_Manual.pdf Binary files differnew file mode 100644 index 0000000..346c348 --- /dev/null +++ b/AppleI_Manual.pdf @@ -2,9 +2,7 @@ TESING PHASE Test how stack works. Create a stack position macro. Once all stack commands are certain, push processor status to stack to be able to debug flags. -Link pthreads library, and segregate work into multiple threads. - -Figure out simple threading in C to run other programs within the same address space. Perhaps use this to let the emulator run as an engine, which is interfaced by swappable clients, such as the SDL terminal emulator, terminal, and instruction interpreter clients. +Make all 6502 related parts even more modular, so as to make it possible to use in other projects if the want arises. diff --git a/docs/interpreter.md b/docs/interpreter.md index 54a6c2a..85ab792 100644 --- a/docs/interpreter.md +++ b/docs/interpreter.md @@ -37,7 +37,6 @@ The only case in which this should be avoided is after an M/m command. The interpreter comes with multiple statements for the purpose of debugging the emulator. `Q/q` Quits the program. -Will cause segfault at end of file if not used. `R/r` Resets the virtual computer. @@ -47,11 +46,19 @@ Will cause segfault at end of file if not used. There are two forms which memory can be printed. The first is `sXX` where `XX` is a memory page. The whole page of memory is printed onto the screen. The second is `sXXXX` where `XXXX` is a specific address. This prints out the value of the 1 byte requested. -Be aware that unallocated memory will be dumped if it happens to be accessed with this command. Also be aware that there should be a newline directly after this command. +Be aware that unallocated memory will be dumped if it happens to be accessed with this command. `S/s` Directly set a piece of memory. Syntax is strictly of form `sXXXX.xx` where `XXXX` is the address and `xx` is the value. `/` Prints until newline. -`#` Ignores until newline.
\ No newline at end of file +`#` Ignores until newline. + +## Anomalies + +I don't care a whole lot about making this interpreter foolproof since its mostly for my personal debugging use. There are a couple anomalies to look out for if you intend to write programs with it. + +1. After M/m command, a newline is *necessary* or it will have unexpected behavior. +2. Two newlines are necessary after single byte-length instructions or it will segfault. +3. If Q/q is not used at the end of a program, it will segfault. It's inconsequential if it does, but it's important to know.
\ No newline at end of file diff --git a/headers/apple.h b/headers/apple.h deleted file mode 100644 index 55ddaa3..0000000 --- a/headers/apple.h +++ /dev/null @@ -1,15 +0,0 @@ -#define MEMORY_SIZE 4096 - -void AppleOn(){ - Memory = calloc(MEMORY_SIZE, sizeof(byte)); - initInstructionTable(); -} - -void AppleReset(){ - acc = 0; X = 0; Y = 0; P = 0; S = 0; - idata.cycles = 0; idata.length = 0; idata.add = 0; idata.value = 0; - free(Memory); - Memory = calloc(MEMORY_SIZE, sizeof(byte)); -} - - diff --git a/headers/include.h b/headers/include.h deleted file mode 100644 index 8f067c2..0000000 --- a/headers/include.h +++ /dev/null @@ -1,9 +0,0 @@ -#include"stdio.h" -#include"stdint.h" -#include"stdlib.h" -#include"string.h" -#include"6502.h" -#include"addressing.h" -#include"instructions/definitions.h" -#include"instructions/table.h" -#include"apple.h"
\ No newline at end of file @@ -1,5 +1,5 @@ default: - gcc interpreter.c -o interpreter + gcc src/interpreter.c -o interpreter illegal: - gcc interpreter.c -o interpreter -D ILLEGAL
\ No newline at end of file + gcc src/interpreter.c -o interpreter -D ILLEGAL diff --git a/src/apple.h b/src/apple.h new file mode 100644 index 0000000..5946374 --- /dev/null +++ b/src/apple.h @@ -0,0 +1,39 @@ +#define MEMORY_SIZE 4096 + +#define XAML 0x24 +#define XAMH 0x25 +#define STL 0x26 +#define STH 0x27 +#define L 0x28 +#define H 0x29 +#define YSAV 0x2A +#define MODE 0x2B + +#define KBD 0xD010 +#define KBD_CR 0xD011 +#define DSP 0xD012 +#define DSP_CR 0xD013 + + +void AppleOn(){ + Memory = calloc(MEMORY_SIZE, sizeof(byte)); + initInstructionTable(); +} + +void AppleReset(){ + acc = 0; X = 0; Y = 0; P = 0; S = 0; + idata.cycles = 0; idata.length = 0; idata.add = 0; idata.value = 0; + free(Memory); + Memory = calloc(MEMORY_SIZE, sizeof(byte)); +} + + + +byte getMemory(address x){ + return Memory[x]; +} + +void setMemory(address x, byte y){ + Memory[x] = y; +} + diff --git a/headers/6502.h b/src/cpu/6502.h index 3a48edc..8ceba29 100644 --- a/headers/6502.h +++ b/src/cpu/6502.h @@ -8,7 +8,7 @@ typedef unsigned short\ byte acc, X, Y, P, S = 0x00; address PC = 0x0000; -byte* Memory; // TO DO. Add expansion capability to memory. +byte* Memory; // FLAGS #define flag_N 0x80 // Negative @@ -43,26 +43,6 @@ void flagClear(byte flag){ } -// BCD -// need to actually look into BCD on the 6502 -byte toBCD(byte x){ - if (x < 100){ - byte a = ((x / 10) << 4); - byte b = (x % 10); - return (a + b); - } - else{ - fprintf(stderr, "Number greater than 99 passed to toBCD()"); - } -} - -byte fromBCD(byte x){ - byte a = ((x >> 4) * 10); - byte b = (x & 0xF); - return (a + b); -} - - // Functions which perform reusable routines for finding if a specific flag should be set. void setFlagN(byte x){ @@ -110,14 +90,14 @@ void setFlagZ(int x){ // Memory Manipulation -//need to add special conditions for D0 and FF +// Are to be defined by the system to handle special cases. + +byte getMemory(address x); +void setMemory(address x, byte y); -byte getMemory(address x){ - return Memory[x]; -} -void setMemory(address x, byte y){ - Memory[x] = y; -} +#include"addressing.h" +#include"instructions/definitions.h" +#include"instructions/table.h"
\ No newline at end of file diff --git a/headers/addressing.h b/src/cpu/addressing.h index c5db440..7a72ff5 100644 --- a/headers/addressing.h +++ b/src/cpu/addressing.h @@ -19,14 +19,14 @@ enum Addressing { typedef int Addressing; -struct AddData{ +typedef struct AddData{ int cycles; int length; address add; byte value; -}; +} AddData; -typedef struct AddData AddData; +//typedef struct AddData AddData; #include"instructions/init.h" diff --git a/headers/instructions/definitions.h b/src/cpu/instructions/definitions.h index 937ca10..937ca10 100644 --- a/headers/instructions/definitions.h +++ b/src/cpu/instructions/definitions.h diff --git a/headers/instructions/illegal/definitions.h b/src/cpu/instructions/illegal/definitions.h index e69de29..e69de29 100644 --- a/headers/instructions/illegal/definitions.h +++ b/src/cpu/instructions/illegal/definitions.h diff --git a/headers/instructions/illegal/init.h b/src/cpu/instructions/illegal/init.h index e69de29..e69de29 100644 --- a/headers/instructions/illegal/init.h +++ b/src/cpu/instructions/illegal/init.h diff --git a/headers/instructions/illegal/table-append.h b/src/cpu/instructions/illegal/table-append.h index e69de29..e69de29 100644 --- a/headers/instructions/illegal/table-append.h +++ b/src/cpu/instructions/illegal/table-append.h diff --git a/headers/instructions/init.h b/src/cpu/instructions/init.h index dd2d477..dd2d477 100644 --- a/headers/instructions/init.h +++ b/src/cpu/instructions/init.h diff --git a/headers/instructions/table.h b/src/cpu/instructions/table.h index f37814b..f37814b 100644 --- a/headers/instructions/table.h +++ b/src/cpu/instructions/table.h diff --git a/headers/debug.h b/src/debug.h index 06d4733..06d4733 100644 --- a/headers/debug.h +++ b/src/debug.h diff --git a/src/include.h b/src/include.h new file mode 100644 index 0000000..815bbf7 --- /dev/null +++ b/src/include.h @@ -0,0 +1,6 @@ +#include"stdio.h" +#include"stdint.h" +#include"stdlib.h" +#include"string.h" +#include"cpu/6502.h" +#include"apple.h"
\ No newline at end of file diff --git a/interpreter.c b/src/interpreter.c index 0261e57..ed6aaee 100644 --- a/interpreter.c +++ b/src/interpreter.c @@ -3,8 +3,8 @@ // Refer to interpreter.md for the manual -#include"headers/include.h" -#include"headers/debug.h" +#include"include.h" +#include"debug.h" //Write a custom getc function here which ignores spaces @@ -105,7 +105,7 @@ int main(int argc, char *argv[]){ c = dCharToNum(c) << 4; c += dCharToNum(getc(stdin)); address x = 0x0000; - char z; + char z = 0x00; for(int i = ((fAddressGetLengthPrempt(c) * 2) - 2); i > 0; i--) { do { z = getc(stdin); diff --git a/test/02-Stack b/test/02-Stack index 037ae10..50c760c 100644 --- a/test/02-Stack +++ b/test/02-Stack @@ -1,2 +1,59 @@ # 02-Stack #This test checks whether each stack operation functions as expected. + +#MNEMONIC HEX +#TXS (Transfer X to Stack ptr) $9A +#TSX (Transfer Stack ptr to X) $BA +#PHA (PusH Accumulator) $48 +#PLA (PuLl Accumulator) $68 +#PHP (PusH Processor status) $08 +#PLP (PuLl Processor status) $28 + +p + +/Push/Pull Accumulator Test + +a9 01 + +48 + +a9 10 + +48 + +68 + +68 + +p + +m01 + +/~~~~TXS/TSX Test + +a27f + +/Status after LDX 7f +p + +9a + +/Status after TXS +p + +68 + +68 + +/Status after 2 PLA +p + +ba + +/Status after TSX +p + +q + + + diff --git a/test/99-WozMon b/test/99-WozMon new file mode 100644 index 0000000..2ddbb24 --- /dev/null +++ b/test/99-WozMon @@ -0,0 +1,260 @@ +;------------------------------------------------------------------------- +; +; The WOZ Monitor for the Apple 1 +; Written by Steve Wozniak 1976 +; +;------------------------------------------------------------------------- + + .CR 6502 + .OR $FF00 + .TF WOZMON.HEX,HEX,8 + +;------------------------------------------------------------------------- +; Memory declaration +;------------------------------------------------------------------------- + +XAML .EQ $24 Last "opened" location Low +XAMH .EQ $25 Last "opened" location High +STL .EQ $26 Store address Low +STH .EQ $27 Store address High +L .EQ $28 Hex value parsing Low +H .EQ $29 Hex value parsing High +YSAV .EQ $2A Used to see if hex value is given +MODE .EQ $2B $00=XAM, $7F=STOR, $AE=BLOCK XAM + +IN .EQ $0200,$027F Input buffer + +KBD .EQ $D010 PIA.A keyboard input +KBDCR .EQ $D011 PIA.A keyboard control register +DSP .EQ $D012 PIA.B display output register +DSPCR .EQ $D013 PIA.B display control register + +; KBD b7..b0 are inputs, b6..b0 is ASCII input, b7 is constant high +; Programmed to respond to low to high KBD strobe +; DSP b6..b0 are outputs, b7 is input +; CB2 goes low when data is written, returns high when CB1 goes high +; Interrupts are enabled, though not used. KBD can be jumpered to IRQ, +; whereas DSP can be jumpered to NMI. + +;------------------------------------------------------------------------- +; Constants +;------------------------------------------------------------------------- + +BS .EQ $DF Backspace key, arrow left key +CR .EQ $8D Carriage Return +ESC .EQ $9B ESC key +PROMPT .EQ "\" Prompt character + +;------------------------------------------------------------------------- +; Let's get started +; +; Remark the RESET routine is only to be entered by asserting the RESET +; line of the system. This ensures that the data direction registers +; are selected. +;------------------------------------------------------------------------- + +RESET CLD Clear decimal arithmetic mode + CLI + LDY #%0111.1111 Mask for DSP data direction reg + STY DSP (DDR mode is assumed after reset) + LDA #%1010.0111 KBD and DSP control register mask + STA KBDCR Enable interrupts, set CA1, CB1 for + STA DSPCR positive edge sense/output mode. + +; Program falls through to the GETLINE routine to save some program bytes +; Please note that Y still holds $7F, which will cause an automatic Escape + +;------------------------------------------------------------------------- +; The GETLINE process +;------------------------------------------------------------------------- + +NOTCR CMP #BS Backspace key? + BEQ BACKSPACE Yes + CMP #ESC ESC? + BEQ ESCAPE Yes + INY Advance text index + BPL NEXTCHAR Auto ESC if line longer than 127 + +ESCAPE LDA #PROMPT Print prompt character + JSR ECHO Output it. + +GETLINE LDA #CR Send CR + JSR ECHO + + LDY #0+1 Start a new input line +BACKSPACE DEY Backup text index + BMI GETLINE Oops, line's empty, reinitialize + +NEXTCHAR LDA KBDCR Wait for key press + BPL NEXTCHAR No key yet! + LDA KBD Load character. B7 should be '1' + STA IN,Y Add to text buffer + JSR ECHO Display character + CMP #CR + BNE NOTCR It's not CR! + +; Line received, now let's parse it + + LDY #-1 Reset text index + LDA #0 Default mode is XAM + TAX X=0 + +SETSTOR ASL Leaves $7B if setting STOR mode + +SETMODE STA MODE Set mode flags + +BLSKIP INY Advance text index + +NEXTITEM LDA IN,Y Get character + CMP #CR + BEQ GETLINE We're done if it's CR! + CMP #"." + BCC BLSKIP Ignore everything below "."! + BEQ SETMODE Set BLOCK XAM mode ("." = $AE) + CMP #":" + BEQ SETSTOR Set STOR mode! $BA will become $7B + CMP #"R" + BEQ RUN Run the program! Forget the rest + STX L Clear input value (X=0) + STX H + STY YSAV Save Y for comparison + +; Here we're trying to parse a new hex value + +NEXTHEX LDA IN,Y Get character for hex test + EOR #$B0 Map digits to 0-9 + CMP #9+1 Is it a decimal digit? + BCC DIG Yes! + ADC #$88 Map letter "A"-"F" to $FA-FF + CMP #$FA Hex letter? + BCC NOTHEX No! Character not hex + +DIG ASL + ASL Hex digit to MSD of A + ASL + ASL + + LDX #4 Shift count +HEXSHIFT ASL Hex digit left, MSB to carry + ROL L Rotate into LSD + ROL H Rotate into MSD's + DEX Done 4 shifts? + BNE HEXSHIFT No, loop + INY Advance text index + BNE NEXTHEX Always taken + +NOTHEX CPY YSAV Was at least 1 hex digit given? + BEQ ESCAPE No! Ignore all, start from scratch + + BIT MODE Test MODE byte + BVC NOTSTOR B6=0 is STOR, 1 is XAM or BLOCK XAM + +; STOR mode, save LSD of new hex byte + + LDA L LSD's of hex data + STA (STL,X) Store current 'store index'(X=0) + INC STL Increment store index. + BNE NEXTITEM No carry! + INC STH Add carry to 'store index' high +TONEXTITEM JMP NEXTITEM Get next command item. + +;------------------------------------------------------------------------- +; RUN user's program from last opened location +;------------------------------------------------------------------------- + +RUN JMP (XAML) Run user's program + +;------------------------------------------------------------------------- +; We're not in Store mode +;------------------------------------------------------------------------- + +NOTSTOR BMI XAMNEXT B7 = 0 for XAM, 1 for BLOCK XAM + +; We're in XAM mode now + + LDX #2 Copy 2 bytes +SETADR LDA L-1,X Copy hex data to + STA STL-1,X 'store index' + STA XAML-1,X and to 'XAM index' + DEX Next of 2 bytes + BNE SETADR Loop unless X = 0 + +; Print address and data from this address, fall through next BNE. + +NXTPRNT BNE PRDATA NE means no address to print + LDA #CR Print CR first + JSR ECHO + LDA XAMH Output high-order byte of address + JSR PRBYTE + LDA XAML Output low-order byte of address + JSR PRBYTE + LDA #":" Print colon + JSR ECHO + +PRDATA LDA #" " Print space + JSR ECHO + LDA (XAML,X) Get data from address (X=0) + JSR PRBYTE Output it in hex format +XAMNEXT STX MODE 0 -> MODE (XAM mode). + LDA XAML See if there's more to print + CMP L + LDA XAMH + SBC H + BCS TONEXTITEM Not less! No more data to output + + INC XAML Increment 'examine index' + BNE MOD8CHK No carry! + INC XAMH + +MOD8CHK LDA XAML If address MOD 8 = 0 start new line + AND #%0000.0111 + BPL NXTPRNT Always taken. + +;------------------------------------------------------------------------- +; Subroutine to print a byte in A in hex form (destructive) +;------------------------------------------------------------------------- + +PRBYTE PHA Save A for LSD + LSR + LSR + LSR MSD to LSD position + LSR + JSR PRHEX Output hex digit + PLA Restore A + +; Fall through to print hex routine + +;------------------------------------------------------------------------- +; Subroutine to print a hexadecimal digit +;------------------------------------------------------------------------- + +PRHEX AND #%0000.1111 Mask LSD for hex print + ORA #"0" Add "0" + CMP #"9"+1 Is it a decimal digit? + BCC ECHO Yes! output it + ADC #6 Add offset for letter A-F + +; Fall through to print routine + +;------------------------------------------------------------------------- +; Subroutine to print a character to the terminal +;------------------------------------------------------------------------- + +ECHO BIT DSP DA bit (B7) cleared yet? + BMI ECHO No! Wait for display ready + STA DSP Output character. Sets DA + RTS + +;------------------------------------------------------------------------- +; Vector area +;------------------------------------------------------------------------- + + .DA $0000 Unused, what a pity +NMI_VEC .DA $0F00 NMI vector +RESET_VEC .DA RESET RESET vector +IRQ_VEC .DA $0000 IRQ vector + +;------------------------------------------------------------------------- + + .LI OFF + |