Created Program.java to hold and manipulate program data. Created Parser.java to contain all methods needed for parsing. Created test.asm as a test 6502 asm file. Changed Processor.java to import test.asm as a program, print the number of instructions, and print the contents of the file.

This commit is contained in:
neoscriptor 2009-04-03 20:09:42 +00:00
parent e976bd809c
commit 9145a37be8
4 changed files with 408 additions and 22 deletions

27
Parser.java Normal file

@ -0,0 +1,27 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Parser.java
* Static class that handles all regex and parsing.
*
* @author Christopher Erickson
*/
public class Parser {
/**
* Returns true if line is an instruction. False otherwise.
*
* @param line The line to be parsed.
* @return True if line contains an instruction.
*/
public static boolean isInstruction( String line ) {
// Setup instruction regex Instruction Operand Comment
// This is not perfect and needs to accomodate symbols
Pattern instruction = Pattern.compile( "^\\s*\\w{3}\\s+\\w*\\s*(;.*)?$" );
Matcher regex = instruction.matcher( line );
if ( regex.matches() )
return true;
return false;
}
}

@ -4,7 +4,6 @@
*
* @author Christopher Erickson and Christopher Pable
*/
import java.util.regex.*;
public class Processor {
/* Registers */ // 0 1 2 3 4 5 6 7
@ -14,6 +13,8 @@ public class Processor {
private Register Y; // Index register
private Register SP; // Stack pointer ( Usage of page $01 implied )
private PC PC; // Program counter
/* Program */
private Program theProgram;
// Default Constructor
public Processor() {
@ -45,10 +46,11 @@ public class Processor {
SP.setVal("$ff");
PC.setVal("%0000000000000000");
// Parse & execute!
// Not yet implemented
executeInstructionAt( PC );
// Read in our program
theProgram = new Program( "test.asm" );
// Print it out
System.out.println( theProgram );
}
// Prints out the value of each register, used for testing
@ -61,28 +63,15 @@ public class Processor {
System.out.println("PC:\t" + PC.getValHex());
}
/*
* Here's the important stuff.
*
* Of course the stuff below (the parsing) is merely an example of what
* I'll be doing. You'll handle things like the ADC method. Notice that
* you will ALWAYS receive three bytes. If I parse a memory address, I will
* use that Word to get the byte in memory it refers to, and then send you
* that, so you will never receive a Word. Only Bytes.
*
*/
// THE FOLLOWING IS MERELY AN EXAMPLE
// Parsing stuff that I would do
private String inst = " adc #$45 ";
public void executeInstructionAt( Word prgAddr ) {
public void execInst( Word prgAddr ) {
// Setup instruction regex Instruction Immediate Comment
Pattern instruction = Pattern.compile( "^\\s*(\\w{3})\\s+#(\\$[0-9abcdef]{1,2})\\s*(;\\w*)?.*$" );
//Pattern instruction = Pattern.compile( "^\\s*(\\w{3})\\s+#(\\$[0-9abcdef]{1,2})\\s*(;\\w*)?.*$" );
// Grabbed matched items
Matcher matched = instruction.matcher( inst );
//Matcher matched = instruction.matcher( inst );
// Call the opcode!
ADC( A, A, new Byte( matched.group(2) ) );
//ADC( A, A, new Byte( matched.group(2) ) );
}
// OPCODE HELPERS

110
Program.java Normal file

@ -0,0 +1,110 @@
/**
* Program.java
* Handles all file reading, writing, and accessing
*
* @author Christopher Erickson
*/
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Vector;
public class Program {
/* Class Variables */
Vector<String> theProgram; // Stores the program.
Vector<Integer> instTable; // Keeps track of where instructions are located in theProgram.
/**
* Creates an instance of Program.
* Reads in fileName as a vector and indexes instructions.
*
* @param fileName Location of the file to be read.
*/
public Program( String fileName ) {
// Read the file in as a vector
theProgram = asmFileToVector( fileName );
// Parse the instructions and index them
instTable = parseInstructions();
System.out.println( "Number of instructions: " + instTable.size() );
}
/**
* Creates a vector from a 6502 asm file.
* Based on code from:
* http://www.java2s.com/Code/Java/File-Input-Output/Filereadandwrite.htm
*
* @param asmFile The full location of the input file.
* @return Vector containing all the lines of the file.
*/
public Vector<String> asmFileToVector( String asmFile ) {
// Okay, maybe there's room for just a little Spaceballs humor :)
Vector<String> victor = new Vector<String>();
String curLine;
try {
File asm = new File( asmFile );
BufferedReader buffReader = new BufferedReader(
new InputStreamReader(
new FileInputStream( asm )));
while ( ( curLine = buffReader.readLine() ) != null ) {
victor.addElement( curLine );
}
buffReader.close();
}
catch (FileNotFoundException ex) {
System.out.println( "File not found!" );
}
catch (IOException ex) {
System.out.println( "I/O Error!" );
}
// Return the vector
return victor;
}
/**
* Creates a vector from a 6502 asm string.
*
* @param asmString The newline-delimited string containing asm.
* @return Vector containing all the lines of the file.
*/
public Vector<String> asmToVector( String asm ) {
Vector<String> victor = new Vector<String>();
String[] asmString = asm.split( "\\n" );
for ( int i = 0; i < asmString.length; i++ ) {
victor.addElement( asmString[i] );
}
return victor;
}
/**
* Creates an ArrayList indicative of the location of instructions in theProgram.
*
* @return ArrayList containing the indicies of instructions.
*/
public Vector<Integer> parseInstructions() {
Vector<Integer> retArray = new Vector<Integer>();
for ( int i = 0; i < theProgram.size(); i++ ) {
if ( Parser.isInstruction( theProgram.get( i ) ) )
retArray.add( i );
}
return retArray;
}
/**
* Returns the program as a newline-delimited string.
*
* @return theProgram as a String.
*/
public String toString() {
String retString = "";
for ( int i = 0; i < theProgram.size(); i++ ) {
retString += theProgram.get( i ) + "\n";
}
return retString;
}
}

260
test.asm Normal file

@ -0,0 +1,260 @@
; Sprite.asm
; A sprite example with drawing routine.
;
; This could be applied to any sprite with
; a little modification.
;
; Keys: WASD - Move mario is that direction
; Q - Quit
;
; by NeoScriptor
start:
; Let's draw Mario, and even move him!
; sprite = mario
lda #<mario
sta sprlow
lda #>mario
sta sprhigh
; Setup coordinates
lda #8
sta xpos
lda #8
sta ypos
; Width & height of sprite
lda #16 ; width
sta width
lda #16 ; height
sta height
mainloop:
; Draw the sprite!
jsr drawSprite
; Get the pressed key
jsr getKey
lda key
cmp #0
beq mainloop
cmp #119
beq wkey
cmp #97
beq akey
cmp #115
beq skey
cmp #100
beq dkey
cmp #113
beq qkey
jmp mainloop
wkey:
; The w key was pressed
; Move the sprite up
lda ypos
cmp #1
bmi mainloop
; Clear the bottom of the sprite
clc
adc height
tay
dey
sty clsrow
jsr clearLine
dec ypos
jmp mainloop
akey:
; The a key was pressed
; Move the sprite left
lda xpos
cmp #0
bmi mainloop
dec xpos
jmp mainloop
skey:
; The s key was pressed
; Move the sprite down
lda ypos
cmp #16
bpl mainloop
; Clear the top of the sprite
tay
sty clsrow
jsr clearLine
inc ypos
jmp mainloop
dkey:
; The d key was pressed
; Move the sprite right
lda xpos
cmp #18
bpl mainloop
inc xpos
jmp mainloop
qkey:
; The q key was pressed
; End
rts
; drawSprite - Draws a sprite
; Note: Can only handle widths that are
; multiples of two. i.e. 2, 4, 8, 16, etc
drawSprite:
; Initialize row & col
lda #0
sta row
lda #0
sta col
; Load the sprite
lda sprlow
sta $40
lda sprhigh
sta $41
drawloop:
; Calculate where to grab data from using
; row & col (width*row)+col
ldy row
lda #1
; Do as many left shifts as it takes to mult
; by the sprite width
rowshift:
tax
tya
asl
tay
txa
asl
cmp width
bne rowshift
; Done multiplying, result in y
; Add col
clc
tya
adc col
tay
lda ($40), y ; Grab this pixel from sprite
sta pixel
; Now we have to calculate where to put it!
; ylookup(row + ypos) + (col + xpos)
; Add row & ypos
lda row
clc
adc ypos
; Get appropriate value from table
asl
tax
lda ylookup, x
sta $50
inx
lda ylookup, x
sta $51
; Add col & xpos
lda $50
clc
adc col
adc xpos
sta $50
lda pixel
ldy #0
sta ($50), y ; Put it on the screen
; Increase the col
inc col
; If col != width, continue looping
lda col
cmp width
bne drawloop
; Otherwise, col = 0, row++
lda #0
sta col
lda row
clc
adc #1
sta row
; If row == height, return
lda row
cmp height
bne drawloop
rts ; return
; drawSprite variables
sprlow: dcb 0
sprhigh: dcb 0
width: dcb 0
height: dcb 0
row: dcb 0
col: dcb 0
pixel: dcb 0
xpos: dcb 0
ypos: dcb 0
; clearLine - Clears the line clsrow
clearLine:
lda clsrow
; Get appropriate value from table
asl
tax
lda ylookup, x
sta $c0
inx
lda ylookup, x
sta $c1
lda #0
ldy #0
sta ($c0), y
ldy #31
clsLoop:
sta ($c0), y
dey
bne clsLoop
rts
; clearLine variables
clsrow: dcb 0
; getKey - Stores the value of the pressed key
getKey:
lda $ff
sta key
lda #0
sta $ff
rts
; getKey variables
key: dcb 0
; Table of mem corresponding to each row
ylookup:
dcb $00,$02,$20,$02,$40,$02,$60,$02
dcb $80,$02,$a0,$02,$c0,$02,$e0,$02
dcb $00,$03,$20,$03,$40,$03,$60,$03
dcb $80,$03,$a0,$03,$c0,$03,$e0,$03
dcb $00,$04,$20,$04,$40,$04,$60,$04
dcb $80,$04,$a0,$04,$c0,$04,$e0,$04
dcb $00,$05,$20,$05,$40,$05,$60,$05
dcb $80,$05,$a0,$05,$c0,$05,$e0,$05
; Sprites
mario: ; 16 x 16
dcb 0,0,0,0,2,2,2,2,2,2,0,0,0,0,0,0
dcb 0,0,0,2,2,2,2,2,2,2,2,2,2,0,0,0
dcb 0,0,0,9,9,9,9,8,8,9,8,0,0,0,0,0
dcb 0,0,9,9,8,9,8,8,8,9,8,8,8,0,0,0
dcb 0,0,9,9,8,9,9,8,8,8,9,8,8,8,0,0
dcb 0,0,9,9,9,8,8,8,8,9,9,9,9,0,0,0
dcb 0,0,0,0,8,8,8,8,8,8,8,8,0,0,0,0
dcb 0,0,0,9,9,9,2,9,9,9,0,0,0,0,0,0
dcb 0,0,9,9,9,9,2,9,9,2,9,9,9,0,0,0
dcb 0,9,9,9,9,9,2,2,2,2,9,9,9,9,0,0
dcb 0,8,8,8,9,2,8,2,2,8,2,9,8,8,0,0
dcb 0,8,8,8,8,2,2,2,2,2,2,8,8,8,0,0
dcb 0,8,8,8,2,2,2,2,2,2,2,2,8,8,0,0
dcb 0,0,0,2,2,2,2,0,2,2,2,2,0,0,0,0
dcb 0,0,9,9,9,9,0,0,0,9,9,9,9,0,0,0
dcb 0,9,9,9,9,9,0,0,0,9,9,9,9,9,0,0