├── LICENSE ├── README.md ├── basic ├── asmtest.bas ├── demo.bas ├── loctest.bas ├── proctest.bas ├── sound.bas ├── sprites.bas └── test.bas ├── bin ├── makebasic.zip ├── rom.bin ├── stub.prg ├── vramc.zip └── x16emu ├── control └── build.info ├── documents ├── 6502 Basic Outline.odt ├── 6502 Basic Outline.pdf ├── CHANGES ├── PCW Benchmarks.odt ├── Reference.odt ├── Reference.pdf ├── TODO ├── assembler │ ├── The 6502 Instruction Set Decoded.html │ ├── asmtest.asm │ ├── assembler.csv │ └── assembler.ods ├── benchmarks.ods ├── general.make ├── graphics │ ├── galaxians │ │ ├── Makefile │ │ ├── demo.gif │ │ ├── enemy.amo │ │ ├── galaxians.amo │ │ ├── galaxians.prg │ │ ├── graphics.amo │ │ ├── make.bat │ │ ├── missile.amo │ │ ├── runtime.prg │ │ ├── sprite.data.amo │ │ ├── sprites │ │ │ ├── bullet.png │ │ │ ├── g1a.png │ │ │ ├── g1b.png │ │ │ ├── g2a.png │ │ │ ├── g2b.png │ │ │ ├── g3a.png │ │ │ ├── g3b.png │ │ │ ├── g4a.png │ │ │ ├── ship.png │ │ │ └── sprites.def │ │ └── sprites0.bin │ ├── graphics │ │ ├── Makefile │ │ ├── gr_mario.png │ │ ├── make.bat │ │ ├── mario.png │ │ ├── na_mario.png │ │ ├── palette.py │ │ ├── palette.txt │ │ ├── runtime.prg │ │ ├── sprite.data.amo │ │ ├── sprites │ │ │ ├── g1a.png │ │ │ ├── g1b.png │ │ │ ├── g2a.png │ │ │ ├── g2b.png │ │ │ ├── g3a.png │ │ │ ├── g3b.png │ │ │ ├── g4a.png │ │ │ ├── ship.png │ │ │ └── sprites.def │ │ ├── sprites0.bin │ │ ├── sq_mario.png │ │ ├── test.amo │ │ └── test.prg │ └── scripts │ │ ├── cvsprite.py │ │ ├── gen6502.py │ │ ├── rasm.py │ │ └── scanner.py ├── mode notes.txt ├── review.list ├── test │ ├── Makefile │ ├── _basic.tokenised │ ├── data.vram │ ├── test.bas │ ├── test.prg │ └── vram │ │ ├── box.png │ │ ├── mario.png │ │ ├── sheet.png │ │ ├── sq_mario.png │ │ └── vram.txt ├── test2 │ ├── bresenham.py │ ├── do.sh │ ├── pages.asm │ ├── pages.lst │ ├── test.asm │ ├── test.lst │ └── test.prg └── vram.txt ├── programs ├── grabber │ ├── Makefile │ ├── _basic.tokenised │ ├── data.vram │ ├── dump.bin │ ├── grabber.bas │ ├── grabber.prg │ └── vram │ │ └── vram.txt └── pong │ ├── Makefile │ ├── _basic.tokenised │ ├── data.vram │ ├── dump.bin │ ├── pong.bas │ ├── pong.prg │ └── vram │ ├── ball.png │ ├── bat1.png │ ├── bat2.png │ └── vram.txt ├── scripts ├── __pycache__ │ ├── tokeniser.cpython-39.pyc │ └── tokens.cpython-39.pyc ├── build │ ├── __main__.py │ ├── __pycache__ │ │ ├── asmdata.cpython-39.pyc │ │ ├── tokendata.cpython-39.pyc │ │ ├── tokeniser.cpython-39.pyc │ │ └── tokens.cpython-39.pyc │ ├── asmdata.py │ ├── asmtables.py │ ├── builder.py │ ├── errorgen.py │ ├── makepgm.py │ ├── tables.py │ ├── tokendata.py │ ├── tokeniser.py │ └── tokens.py ├── languages │ └── english.txt ├── miscellaneous │ ├── analyse.py │ ├── callcheck.py │ ├── dumpvar.py │ ├── revcheck.py │ └── testvram.py ├── tests │ ├── __pycache__ │ │ ├── testcore.cpython-39.pyc │ │ └── tokeniser.cpython-39.pyc │ ├── testarr.py │ ├── testarr2.py │ ├── testbin.py │ ├── testcore.py │ ├── testprec.py │ ├── teststr.py │ ├── teststrbin.py │ ├── testtok.py │ ├── testun.py │ └── testvar.py └── vramc │ ├── __main__.py │ ├── __pycache__ │ ├── data.cpython-39.pyc │ ├── encoder.cpython-39.pyc │ ├── palette.cpython-39.pyc │ ├── vramc.cpython-39.pyc │ └── vramfile.cpython-39.pyc │ ├── data.py │ ├── encoder.py │ ├── gr_mario.png │ ├── mario.png │ ├── na_mario.png │ ├── palette.py │ ├── sq_mario.png │ ├── test.vram │ ├── tester.py │ ├── vramc.py │ └── vramfile.py ├── source ├── Makefile ├── assembler │ ├── asmconst.inc │ ├── asmoperand.asm │ ├── asmwrite.asm │ ├── assemblecmd.asm │ ├── assemblelabel.asm │ ├── assembler.asm │ ├── assembler.inc │ └── subgroup.asm ├── basic.asm ├── bin │ ├── basic.lbl │ ├── basic.lst │ ├── basic.prg │ ├── files.list │ ├── rom.bin │ ├── stub.prg │ └── x16emu ├── data.vram ├── device │ ├── device.asm │ ├── device.inc │ └── option_x16 │ │ ├── x16break.asm │ │ ├── x16const.inc │ │ ├── x16file.asm │ │ ├── x16io.asm │ │ └── x16timer.asm ├── doall ├── doall.bat ├── error │ ├── error.asm │ ├── error.inc │ ├── errorhandler.asm │ └── errorhandler.inc ├── extension │ ├── extension.asm │ ├── extension.inc │ ├── extensionhandler.asm │ ├── graphics │ │ ├── general.asm │ │ ├── line.asm │ │ ├── plot.asm │ │ ├── rectframe.asm │ │ ├── renderer.asm │ │ └── utils.asm │ └── option_x16 │ │ ├── driver │ │ ├── coords.asm │ │ └── driver.asm │ │ ├── miscellany │ │ ├── clock.asm │ │ └── joystick.asm │ │ ├── sound │ │ ├── sndqueue.asm │ │ ├── sndunary.asm │ │ ├── sndutils.asm │ │ ├── sound.asm │ │ └── soundsync.asm │ │ ├── sprites │ │ ├── collide.asm │ │ ├── sprite.asm │ │ ├── spritedraw.asm │ │ ├── spritemove.asm │ │ └── spriteutils.asm │ │ ├── video │ │ ├── imagedef.asm │ │ ├── mode.asm │ │ ├── palette.asm │ │ ├── textdraw.asm │ │ ├── vload.asm │ │ ├── vpeekpoke.asm │ │ └── vramprocess.asm │ │ └── x16const.inc ├── floatingpoint │ ├── addsub.asm │ ├── compare.asm │ ├── convert.asm │ ├── float.inc │ ├── floatingpoint.asm │ ├── floatingpoint.inc │ ├── importexport.asm │ ├── loadstore.asm │ ├── muldiv.asm │ └── unary.asm ├── footer │ ├── 99end.asm │ ├── footer.asm │ └── footer.inc ├── generated │ ├── asmconst.inc │ ├── asmtables.inc │ ├── binarystructinfo.inc │ ├── errorid.inc │ ├── errortext.inc │ ├── initialiseall.asm │ ├── installed.inc │ ├── testcode.bin │ ├── testcode.inc │ ├── tokenconst.inc │ ├── tokentext0.inc │ ├── tokentext1.inc │ ├── tokentext2.inc │ ├── tokentext3.inc │ ├── tokenvectors0.inc │ ├── tokenvectors1.inc │ ├── tokenvectors2.inc │ ├── tokenvectors3.inc │ └── toktest.inc ├── header │ ├── 00start.asm │ ├── 01common.inc │ ├── 02macros.inc │ ├── 03data.inc │ ├── header.asm │ └── header.inc ├── interaction │ ├── cold.asm │ ├── delete.asm │ ├── insert.asm │ ├── interaction.asm │ ├── interaction.inc │ └── warm.asm ├── main │ ├── commands │ │ ├── compat │ │ │ ├── readdata.asm │ │ │ └── transfer.asm │ │ ├── io │ │ │ ├── input.asm │ │ │ ├── print.asm │ │ │ ├── text.asm │ │ │ └── vdu.asm │ │ ├── link.asm │ │ ├── misc │ │ │ ├── assert.asm │ │ │ ├── dim.asm │ │ │ ├── let.asm │ │ │ ├── poke.asm │ │ │ ├── rem.asm │ │ │ └── stopend.asm │ │ ├── structures │ │ │ ├── for.asm │ │ │ ├── if.asm │ │ │ ├── local.asm │ │ │ ├── proc.asm │ │ │ ├── proctable.asm │ │ │ ├── repeat.asm │ │ │ ├── scanner.asm │ │ │ └── while.asm │ │ └── system │ │ │ ├── clear.asm │ │ │ ├── list.asm │ │ │ ├── loadsave.asm │ │ │ ├── new.asm │ │ │ └── run.asm │ ├── evaluate │ │ ├── binary │ │ │ ├── binary.asm │ │ │ └── compare.asm │ │ ├── dereference.asm │ │ ├── evaluate.asm │ │ ├── support.asm │ │ └── unary │ │ │ ├── convert.asm │ │ │ ├── event.asm │ │ │ ├── unary.asm │ │ │ ├── unary2.asm │ │ │ └── unarystr.asm │ ├── imath │ │ ├── int32binary.asm │ │ ├── int32compare.asm │ │ ├── int32divide.asm │ │ ├── int32fromstr.asm │ │ ├── int32math.asm │ │ ├── int32multiply.asm │ │ ├── int32tostr.asm │ │ └── int32unary.asm │ ├── main.asm │ ├── main.inc │ └── utility │ │ ├── check.asm │ │ ├── stack.asm │ │ └── warmstart.asm ├── string │ ├── functions │ │ ├── chr.asm │ │ ├── compare.asm │ │ ├── concat.asm │ │ ├── memory.asm │ │ ├── memory.inc │ │ ├── setcase.asm │ │ ├── substring.asm │ │ └── write.asm │ ├── string.asm │ └── string.inc ├── tokeniser │ ├── detokenise │ │ ├── colouring.inc │ │ ├── detokenise.asm │ │ ├── dtprint.asm │ │ ├── identifier.asm │ │ └── token.asm │ ├── tokenise │ │ ├── search.asm │ │ ├── test.asm │ │ ├── tokenise.asm │ │ ├── tokident.asm │ │ ├── tokinteger.asm │ │ ├── tokpunct.asm │ │ └── tokstring.asm │ ├── tokeniser.asm │ ├── tokeniser.inc │ └── tokentext.asm ├── variable │ ├── (unused) array code v1 │ │ ├── access.asm │ │ └── create.asm │ ├── array │ │ ├── access.asm │ │ └── create.asm │ ├── variable.asm │ ├── variable.inc │ └── variable │ │ ├── access.asm │ │ ├── create.asm │ │ ├── find.asm │ │ └── reset.asm └── vram │ ├── box.png │ ├── mario.png │ ├── sheet.png │ ├── sq_mario.png │ └── vram.txt └── test ├── _basic.tokenised ├── basic.prg ├── go ├── go.bat ├── makebasic.zip ├── stub.prg ├── test.bas └── vramc.zip /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 paulscottrobson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 6502-basic 2 | An open source 6502 compatible modern BASIC 3 | -------------------------------------------------------------------------------- /basic/demo.bas: -------------------------------------------------------------------------------- 1 | mode 3 2 | repeat 3 | cls:ink 1 4 | rect 1,1 to 100,100:ink 2 5 | print joy.x(0),joy.y(0),joy.b(0,0),joy.b(0,1),joy.b(0,2),joy.b(0,3) 6 | print joy.x(1),joy.y(1),joy.b(1,0),joy.b(1,1),joy.b(1,2),joy.b(1,3) 7 | until false -------------------------------------------------------------------------------- /basic/loctest.bas: -------------------------------------------------------------------------------- 1 | x1 =42:n$ = "JIM" 2 | print x1,n$ 3 | proc test() 4 | print x1,n$,zz 5 | repeat:until false 6 | 7 | defproc test() 8 | print x1,n$ 9 | proc chx1() 10 | print x1,n$ 11 | local x1,n$,zz 12 | x1 = -1:n$ = "ERIC":zz = &1A7 13 | proc chx1() 14 | print x1,n$,zz 15 | endproc 16 | 17 | defproc chx1() 18 | local x1:x1 = 0:print "(";x1;")" 19 | endproc -------------------------------------------------------------------------------- /basic/proctest.bas: -------------------------------------------------------------------------------- 1 | a1 = -99 2 | x = -2 3 | c1$ = "SAVEME" 4 | print "START",a1,c1$,x 5 | proc show() 6 | proc demo(42,&12345678,"INDEMO!!") 7 | proc show() 8 | print "END",a1,c1$,x 9 | proc show() 10 | c1$ = "xxxxxxxxxxxxxAAAAAA"+"!" 11 | print c1$,len(c1$) 12 | proc show() 13 | repeat:until False 14 | 15 | defproc demo(a1,x,c1$) 16 | proc show() 17 | c1$ = c1$ + "!!!!" 18 | proc show() 19 | proc xo2("*") 20 | print "DEMO",a1,ca1$,"$";str$(x,16),"$"str$(@c1$,16) 21 | endproc 22 | 23 | defproc xo2(c1$) 24 | print "XO2";c1$ 25 | endproc 26 | 27 | defproc show() 28 | a = @c1$ 29 | print "$";str$(deek(a),16),peek(deek(a)-1) 30 | endproc 31 | 32 | -------------------------------------------------------------------------------- /basic/sound.bas: -------------------------------------------------------------------------------- 1 | n = 1 2 | for i = 1 to 5 3 | sound at 1181*n for 5 4 | n = n * 2 5 | next i 6 | repeat 7 | cls:for i = 0 to 15:print playing(i):next i 8 | print playing() 9 | until inkey$ <> "" 10 | end 11 | psg = &1F9C0 12 | vdoke psg,1181 13 | vpoke psg+2,&C0+63 14 | vpoke psg+3,&00+63 15 | a$ = get$():vpoke psg+2,0+63:end 16 | 17 | ;volume nnn 18 | ;sound channel,pitch,duration[,type] -------------------------------------------------------------------------------- /basic/sprites.bas: -------------------------------------------------------------------------------- 1 | 2 | mode 1 3 | sprite true:sprite clear 4 | vload "data.vram" 5 | 6 | x = 200:y = 180 7 | 8 | sprite 1 image 2 to 100,40 9 | sprite 2 image 2 to x,y 10 | 11 | print sprite.x(2) 12 | event1 = 0 13 | while hit(1,2) = 0 14 | y = y - 1:x = x - 1 15 | sprite 2 to x,y 16 | wend 17 | 18 | a$ = get$() 19 | end -------------------------------------------------------------------------------- /bin/makebasic.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/bin/makebasic.zip -------------------------------------------------------------------------------- /bin/rom.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/bin/rom.bin -------------------------------------------------------------------------------- /bin/stub.prg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/bin/stub.prg -------------------------------------------------------------------------------- /bin/vramc.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/bin/vramc.zip -------------------------------------------------------------------------------- /bin/x16emu: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/bin/x16emu -------------------------------------------------------------------------------- /documents/6502 Basic Outline.odt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/documents/6502 Basic Outline.odt -------------------------------------------------------------------------------- /documents/6502 Basic Outline.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/documents/6502 Basic Outline.pdf -------------------------------------------------------------------------------- /documents/PCW Benchmarks.odt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/documents/PCW Benchmarks.odt -------------------------------------------------------------------------------- /documents/Reference.odt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/documents/Reference.odt -------------------------------------------------------------------------------- /documents/Reference.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/documents/Reference.pdf -------------------------------------------------------------------------------- /documents/TODO: -------------------------------------------------------------------------------- 1 | TODO 2 | ==== 3 | - Write some games of some type 4 | - M/C interface to various functions. 5 | - Finish outstanding code reviews 6 | - Add whatever you think necessary as you go. 7 | 8 | => 0.40 9 | 10 | Something like AMOS's Animation thing, animate basic movement, destroy ? looping ? 11 | 12 | Known Bugs 13 | ========== 14 | Mode should do a clear screen as well (when called as instruction, not ForceMode0) 15 | 16 | Tokeniser/Detokeniser needs to support % and a default type, which is hard coded at present. 17 | 18 | DATA in odd places in structures won't work. May need own scanner. 19 | 20 | Break on/off will disable sound interrupt too. 21 | 22 | Incomplete but hooked in for write and test 23 | =========================================== 24 | Special case 1 character in concrete ??? 25 | 26 | All floating point operations. Note Shift-3 dispatches automatically to 27 | extension. Needs cross dispatch to FP routines ? 28 | 29 | Notes 30 | ===== 31 | 32 | New commands/Changes to document 33 | ================================ 34 | 35 | -------------------------------------------------------------------------------- /documents/assembler/assembler.ods: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/documents/assembler/assembler.ods -------------------------------------------------------------------------------- /documents/benchmarks.ods: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/documents/benchmarks.ods -------------------------------------------------------------------------------- /documents/general.make: -------------------------------------------------------------------------------- 1 | # ************************************************************************************************ 2 | # ************************************************************************************************ 3 | # 4 | # Name: general.make 5 | # Purpose: Common Makefile includes. 6 | # Created: 21st February 2021 7 | # Author: Paul Robson (paul@robsons.org.uk) 8 | # 9 | # ************************************************************************************************ 10 | # ************************************************************************************************ 11 | 12 | ifeq ($(OS),Windows_NT) 13 | CCOPY = copy 14 | CMAKE = make 15 | CDEL = del /Q 16 | CDELQ = >NUL 17 | APPSTEM = .exe 18 | S = \\ 19 | else 20 | CCOPY = cp 21 | CDEL = rm -f 22 | CDELQ = 23 | CMAKE = make 24 | APPSTEM = 25 | S = / 26 | endif 27 | # 28 | # Root directory 29 | # 30 | ROOTDIR = ..$(S) 31 | # 32 | # Script to run emulator, expecting parameter to follow 33 | # 34 | EMULATOR = $(ROOTDIR)bin$(S)x16emu -keymap en-gb -dump R -debug -run -scale 2 -prg 35 | # 36 | # Current assembler 37 | # 38 | ASM = 64tass 39 | # 40 | # Source directory 41 | # 42 | SOURCEDIR = $(ROOTDIR)source$(S) 43 | # 44 | # BASIC program directory 45 | # 46 | BASICDIR = $(ROOTDIR)basic$(S) -------------------------------------------------------------------------------- /documents/graphics/galaxians/Makefile: -------------------------------------------------------------------------------- 1 | ifeq ($(OS),Windows_NT) 2 | CCOPY = copy 3 | CCOPYQ = >NUL 4 | CMAKE = mingw32-make 5 | S = \\ 6 | else 7 | CCOPY = cp 8 | CCOPYQ = 9 | CMAKE = make 10 | S = / 11 | endif 12 | 13 | PRGFILE = galaxians.prg 14 | SOURCE = sprite.data.amo graphics.amo enemy.amo missile.amo galaxians.amo 15 | 16 | .PHONY : all 17 | 18 | all : $(PRGFILE) 19 | 20 | run : $(PRGFILE) 21 | ..$(S)bin$(S)x16emu -debug -prg $(PRGFILE) -scale 2 -run 22 | 23 | gif : $(PRGFILE) 24 | ..$(S)bin$(S)x16emu -debug -prg $(PRGFILE) -scale 2 -run -gif demo.gif 25 | 26 | sprite.data.amo : sprites$(S)/sprites.def 27 | python ..$(S)/scripts/$(S)/cvsprite.py 28 | 29 | $(PRGFILE) : $(SOURCE) 30 | $(CMAKE) -C ..$(S)runtime 31 | $(CCOPY) ..$(S)bin$(S)runtime.prg . $(CCOPYQ) 32 | python ..$(S)bin$(S)amoral.zip -n -o $@ -s $(SOURCE) -------------------------------------------------------------------------------- /documents/graphics/galaxians/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/documents/graphics/galaxians/demo.gif -------------------------------------------------------------------------------- /documents/graphics/galaxians/galaxians.amo: -------------------------------------------------------------------------------- 1 | var formation.event # formation event timer 2 | var dive.event 3 | var attack.event 4 | 5 | slow proc main() { 6 | 7 | initialise.display() 8 | enemy.list.initialise() 9 | enemy.list.reset() 10 | missile.reset(10) 11 | 12 | 0 -> formation.event -> dive.event -> attack.event 13 | while (0 == 0) { 14 | if (event(@formation.event,10) < 0) { 15 | enemy.move.formation() 16 | missile.fire() 17 | } 18 | if (event(@dive.event,3) < 0) { 19 | enemy.move.attackers() 20 | missile.move.all() 21 | } 22 | if (event(@attack.event,120) < 0) { 23 | enemy.launch.attack() 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /documents/graphics/galaxians/galaxians.prg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/documents/graphics/galaxians/galaxians.prg -------------------------------------------------------------------------------- /documents/graphics/galaxians/graphics.amo: -------------------------------------------------------------------------------- 1 | 2 | # *********************************************************************************** 3 | # 4 | # Load VRAM from memory address to page:target address, count bytes. 5 | # 6 | # *********************************************************************************** 7 | 8 | fast 9 | 10 | proc load.vram(from,page,to,count) { 11 | times (count) { 12 | poke.v(page,to,peek.b(from)) 13 | from ++ -> from 14 | to ++ -> to 15 | } 16 | } 17 | 18 | # *********************************************************************************** 19 | # 20 | # Load in a spritesn.bin file 21 | # 22 | # *********************************************************************************** 23 | 24 | proc load.data(spriteFile,page1addr) { 25 | spriteFile 26 | [["DA7AAA A90C20BDFF"]] # phx ply tax lda #12 jsr $FFBD 27 | [["A901A208A00020BAFF"]] # lda #1,ldx #8,ldy #0, jsr $FFBA 28 | [["A900A200A0A020D5FF"]] # lda #0,ldx #$0,ldy #$A0, jsr $FFD5 29 | load.vram($A000,1,$FA00,32) # load standard palette 30 | load.vram($A000,1,page1addr,spr.bytes) # load the data in. 31 | } 32 | 33 | slow 34 | 35 | # *********************************************************************************** 36 | # 37 | # Event trigger. if (pEvent) is zero initialise, if timed out reinitialise 38 | # and return true. 39 | # 40 | # *********************************************************************************** 41 | 42 | fast 43 | 44 | func event(pEvent,rate) { 45 | var p,r peek.w(pEvent) -> p false->r 46 | if (p == 0) { 47 | read.timer()=>p 48 | } 49 | if (read.timer()-p >= 0) { 50 | p +rate => p 51 | true -> r 52 | } 53 | poke.w(pEvent,p) 54 | r 55 | } 56 | 57 | slow 58 | 59 | # *********************************************************************************** 60 | # 61 | # Initialise Game Display 62 | # 63 | # *********************************************************************************** 64 | 65 | proc initialise.display() { 66 | 67 | print.character($90) 68 | print.character(1) 69 | print.character(147) 70 | 71 | poke.b($9f29,$61) # layer 2 on sprites on 72 | poke.b($9f2a,$40) # double normal scale 73 | poke.b($9f2b,$40) 74 | 75 | load.data("sprites0.bin",0) 76 | } 77 | -------------------------------------------------------------------------------- /documents/graphics/galaxians/make.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | mingw32-make %* -------------------------------------------------------------------------------- /documents/graphics/galaxians/missile.amo: -------------------------------------------------------------------------------- 1 | # *********************************************************************************** 2 | # 3 | # Globals 4 | # 5 | # *********************************************************************************** 6 | 7 | struct missile { 8 | x,y, # position (x < 0 = unused) 9 | sprite.addr # sprite address. 10 | } 11 | 12 | const MISSILE.MAX 16 13 | 14 | var missile.list # array of missiles. 15 | var missile.count # active missiles. 16 | 17 | # *********************************************************************************** 18 | # 19 | # Reset missiles 20 | # 21 | # *********************************************************************************** 22 | 23 | proc missile.reset(c) { 24 | var n,a 25 | c -> missile.count 26 | if (missile.list == 0) { 27 | alloc(MISSILE.MAX*2) => missile.list 28 | times(MISSILE.MAX,n) { 29 | poke.w(missile.list[n],missile.new()) 30 | missile.w_x(0) 31 | missile.w_sprite.addr(n << << << +$FE00=>a) 32 | poke.vw(1,a+6,0) 33 | } 34 | } 35 | } 36 | 37 | # *********************************************************************************** 38 | # 39 | # Fire missile from random enemy 40 | # 41 | # *********************************************************************************** 42 | 43 | proc missile.fire() { 44 | var a,n 45 | times(missile.count,n) { 46 | missile.use(peek.w(missile.list[n])) 47 | if (missile.r_x() == 0) { 48 | random() & 63 -> a 49 | if (a-ENEMY.MAX < 0) { 50 | enemy.use(peek.w(enemy.list[a])) 51 | if (enemy.r_state() >= 0) { 52 | missile.w_x(enemy.r_x()) 53 | missile.w_y(enemy.r_y()) 54 | } 55 | } 56 | } 57 | } 58 | } 59 | 60 | # *********************************************************************************** 61 | # 62 | # Move all missiles 63 | # 64 | # *********************************************************************************** 65 | 66 | fast 67 | proc missile.move.all() { 68 | var n,s,x 69 | times(missile.count,n) { 70 | missile.use(peek.w(missile.list[n])) 71 | if (missile.r_x() <> 0) { 72 | missile.r_sprite.addr() -> s 73 | missile.w_y(missile.r_y()+5) 74 | poke.vw(1,s,spr.bullet) 75 | poke.vw(1,s+2,missile.r_x()) 76 | poke.vw(1,s+4,missile.r_y()) 77 | poke.vw(1,s+6,$500c) 78 | if (missile.r_y() >= 240) { missile.w_x(0) } 79 | } 80 | } 81 | } 82 | slow -------------------------------------------------------------------------------- /documents/graphics/galaxians/runtime.prg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/documents/graphics/galaxians/runtime.prg -------------------------------------------------------------------------------- /documents/graphics/galaxians/sprite.data.amo: -------------------------------------------------------------------------------- 1 | const spr.g1a 2049 2 | const spr.g2a 2053 3 | const spr.g3a 2057 4 | const spr.g1b 2061 5 | const spr.g2b 2065 6 | const spr.g3b 2069 7 | const spr.g4a 2073 8 | const spr.ship 2077 9 | const spr.bullet 2093 10 | const spr.bytes 1568 11 | -------------------------------------------------------------------------------- /documents/graphics/galaxians/sprites/bullet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/documents/graphics/galaxians/sprites/bullet.png -------------------------------------------------------------------------------- /documents/graphics/galaxians/sprites/g1a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/documents/graphics/galaxians/sprites/g1a.png -------------------------------------------------------------------------------- /documents/graphics/galaxians/sprites/g1b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/documents/graphics/galaxians/sprites/g1b.png -------------------------------------------------------------------------------- /documents/graphics/galaxians/sprites/g2a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/documents/graphics/galaxians/sprites/g2a.png -------------------------------------------------------------------------------- /documents/graphics/galaxians/sprites/g2b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/documents/graphics/galaxians/sprites/g2b.png -------------------------------------------------------------------------------- /documents/graphics/galaxians/sprites/g3a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/documents/graphics/galaxians/sprites/g3a.png -------------------------------------------------------------------------------- /documents/graphics/galaxians/sprites/g3b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/documents/graphics/galaxians/sprites/g3b.png -------------------------------------------------------------------------------- /documents/graphics/galaxians/sprites/g4a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/documents/graphics/galaxians/sprites/g4a.png -------------------------------------------------------------------------------- /documents/graphics/galaxians/sprites/ship.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/documents/graphics/galaxians/sprites/ship.png -------------------------------------------------------------------------------- /documents/graphics/galaxians/sprites/sprites.def: -------------------------------------------------------------------------------- 1 | # 2 | # Sprites Definition file. 3 | # 4 | size = 16 # sets the target sprite size to 16x16 (default 16) 5 | pos = C # centre position (B is centre bottom) (default B) 6 | scale = 0.3 # scale if not fitted (default 0 to fit) 7 | 8 | g1a.png 9 | g2a.png 10 | g3a.png 11 | g1b.png 12 | g2b.png 13 | g3b.png 14 | g4a.png 15 | 16 | size = 32 17 | scale = 0.32 18 | 19 | ship.png 20 | 21 | size = 16 22 | bullet.png 23 | -------------------------------------------------------------------------------- /documents/graphics/galaxians/sprites0.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/documents/graphics/galaxians/sprites0.bin -------------------------------------------------------------------------------- /documents/graphics/graphics/Makefile: -------------------------------------------------------------------------------- 1 | ifeq ($(OS),Windows_NT) 2 | CCOPY = copy 3 | CCOPYQ = >NUL 4 | CMAKE = mingw32-make 5 | S = \\ 6 | else 7 | CCOPY = cp 8 | CCOPYQ = 9 | CMAKE = make 10 | S = / 11 | endif 12 | 13 | PRGFILE = test.prg 14 | 15 | .PHONY : all 16 | 17 | all : $(PRGFILE) 18 | 19 | run : $(PRGFILE) 20 | ..$(S)bin$(S)x16emu -debug -prg $(PRGFILE) -scale 2 -run 21 | 22 | gif : $(PRGFILE) 23 | ..$(S)bin$(S)x16emu -debug -prg $(PRGFILE) -scale 2 -run -gif demo.gif 24 | 25 | palette.amo : palette.py 26 | python palette.py 27 | 28 | $(PRGFILE) : sprite.data.amo test.amo 29 | $(CMAKE) -C ..$(S)runtime 30 | $(CCOPY) ..$(S)bin$(S)runtime.prg . $(CCOPYQ) 31 | python ..$(S)bin$(S)amoral.zip -o $@ -s $^ -------------------------------------------------------------------------------- /documents/graphics/graphics/gr_mario.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/documents/graphics/graphics/gr_mario.png -------------------------------------------------------------------------------- /documents/graphics/graphics/make.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | mingw32-make %* -------------------------------------------------------------------------------- /documents/graphics/graphics/mario.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/documents/graphics/graphics/mario.png -------------------------------------------------------------------------------- /documents/graphics/graphics/na_mario.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/documents/graphics/graphics/na_mario.png -------------------------------------------------------------------------------- /documents/graphics/graphics/palette.py: -------------------------------------------------------------------------------- 1 | # ******************************************************************************************* 2 | # ******************************************************************************************* 3 | # 4 | # File: palette.py 5 | # Date: 20th November 2020 6 | # Purpose: Standard 16 colour palette not designed for NTSC televisions 7 | # Author: Paul Robson (paul@robson.org.uk) 8 | # 9 | # ******************************************************************************************* 10 | # ******************************************************************************************* 11 | 12 | import re 13 | # 14 | # Convert a palette value into 4 bit. 15 | # 16 | def pv(n): 17 | return int((n+7.5)*15/255.0) 18 | # 19 | # Convert RGB: n,n,n into 4 bit tuple. 20 | # 21 | def process(p): 22 | m = re.match("^RGB\\:\\s*(\\d+)\\,\\s*(\\d+)\\,\\s*(\\d+)\\s*$",p) 23 | assert m is not None,p 24 | return [int(x) for x in m.groups()] 25 | # 26 | # Raw RGB colour data for my palette. 27 | # 28 | rawData = """ 29 | Black/Transparent. 30 | RGB: 0, 0, 0 31 | Red 32 | RGB: 255,0,0 33 | Green 34 | RGB: 0,255,0 35 | Yellow 36 | RGB: 255, 255,0 37 | Blue 38 | RGB: 0,0,255 39 | Purple 40 | RGB: 255,0,255 41 | Cyan 42 | RGB: 0,255,255 43 | White 44 | RGB: 255, 255, 255 45 | 46 | Black 47 | RGB: 0, 0, 0 48 | Dk. Gray 49 | RGB: 87, 87, 87 50 | Lt. Gray 51 | RGB: 160, 160, 160 52 | Orange 53 | RGB: 255, 128, 0 54 | Brown 55 | RGB: 150, 70, 20 56 | Lt. Green 57 | RGB: 128, 255, 0 58 | Lt. Blue 59 | RGB: 0,128,255 60 | Pink 61 | RGB: 255, 205, 243 62 | """ 63 | 64 | p = [x.strip() for x in rawData.split("\n") if x.find("RGB") >= 0] 65 | assert len(p) == 16 66 | p = [process(x) for x in p] 67 | # 68 | # Python format. 69 | # 70 | h = open("palette.txt","w") 71 | h.write("#\n#\tPython format\n#\t\n{0}\n\n".format(str(p))) 72 | h.close() 73 | # 74 | # Four bit format. 75 | # 76 | p = [ [pv(x[0]),pv(x[1]),pv(x[2])] for x in p] 77 | p = [ x[1]*4096+x[2]*256+x[0] for x in p] 78 | p = ["{0:04x}".format(x) for x in p] 79 | h = open("palette.amo","w") 80 | h.write("code proc default.palette() {\n") 81 | h.write("\t[[\"{0}\"]]\n}}\n".format(" ".join(p))) 82 | h.close() 83 | 84 | -------------------------------------------------------------------------------- /documents/graphics/graphics/palette.txt: -------------------------------------------------------------------------------- 1 | # 2 | # Python format 3 | # 4 | [[0, 0, 0], [255, 0, 0], [0, 255, 0], [255, 255, 0], [0, 0, 255], [255, 0, 255], [0, 255, 255], [255, 255, 255], [0, 0, 0], [87, 87, 87], [160, 160, 160], [255, 128, 0], [150, 70, 20], [128, 255, 0], [0, 128, 255], [255, 205, 243]] 5 | 6 | -------------------------------------------------------------------------------- /documents/graphics/graphics/runtime.prg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/documents/graphics/graphics/runtime.prg -------------------------------------------------------------------------------- /documents/graphics/graphics/sprite.data.amo: -------------------------------------------------------------------------------- 1 | const spr.g1a 2049 2 | const spr.g2a 2053 3 | const spr.g3a 2057 4 | const spr.g1b 2061 5 | const spr.g2b 2065 6 | const spr.g3b 2069 7 | const spr.g4a 2073 8 | const spr.ship 2077 9 | const spr.bytes 1440 10 | -------------------------------------------------------------------------------- /documents/graphics/graphics/sprites/g1a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/documents/graphics/graphics/sprites/g1a.png -------------------------------------------------------------------------------- /documents/graphics/graphics/sprites/g1b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/documents/graphics/graphics/sprites/g1b.png -------------------------------------------------------------------------------- /documents/graphics/graphics/sprites/g2a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/documents/graphics/graphics/sprites/g2a.png -------------------------------------------------------------------------------- /documents/graphics/graphics/sprites/g2b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/documents/graphics/graphics/sprites/g2b.png -------------------------------------------------------------------------------- /documents/graphics/graphics/sprites/g3a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/documents/graphics/graphics/sprites/g3a.png -------------------------------------------------------------------------------- /documents/graphics/graphics/sprites/g3b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/documents/graphics/graphics/sprites/g3b.png -------------------------------------------------------------------------------- /documents/graphics/graphics/sprites/g4a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/documents/graphics/graphics/sprites/g4a.png -------------------------------------------------------------------------------- /documents/graphics/graphics/sprites/ship.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/documents/graphics/graphics/sprites/ship.png -------------------------------------------------------------------------------- /documents/graphics/graphics/sprites/sprites.def: -------------------------------------------------------------------------------- 1 | # 2 | # Sprites Definition file. 3 | # 4 | size = 16 # sets the target sprite size to 16x16 (default 16) 5 | pos = C # centre position (B is centre bottom) (default B) 6 | scale = 0.3 # scale if not fitted (default 0 to fit) 7 | 8 | g1a.png 9 | g2a.png 10 | g3a.png 11 | g1b.png 12 | g2b.png 13 | g3b.png 14 | g4a.png 15 | 16 | size = 32 17 | scale = 0.32 18 | 19 | ship.png -------------------------------------------------------------------------------- /documents/graphics/graphics/sprites0.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/documents/graphics/graphics/sprites0.bin -------------------------------------------------------------------------------- /documents/graphics/graphics/sq_mario.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/documents/graphics/graphics/sq_mario.png -------------------------------------------------------------------------------- /documents/graphics/graphics/test.amo: -------------------------------------------------------------------------------- 1 | # 2 | # Load VRAM from memory address to page:target address, count bytes. 3 | # 4 | fast proc load.vram(from,page,to,count) { 5 | times (count) { 6 | poke.v(page,to,peek.b(from)) 7 | from ++ -> from 8 | to ++ -> to 9 | } 10 | } 11 | # 12 | # Load in a spritesn.bin file 13 | # 14 | fast proc load.data(spriteFile,page1addr) { 15 | spriteFile 16 | [["DA7AAA A90C20BDFF"]] # phx ply tax lda #12 jsr $FFBD 17 | [["A901A208A00020BAFF"]] # lda #1,ldx #8,ldy #0, jsr $FFBA 18 | [["A900A200A0A020D5FF"]] # lda #0,ldx #$0,ldy #$A0, jsr $FFD5 19 | load.vram($A000,1,$FA00,32) # load standard palette 20 | load.vram($A000,1,page1addr,spr.bytes) # load the data in. 21 | } 22 | 23 | slow 24 | 25 | proc init.sprite(spr,y) { 26 | poke.vw(1,spr,spr.g1a) # Address / 32 in first two bytes. 27 | poke.vw(1,spr+2,y*16) # X 28 | poke.vw(1,spr+4,64) # Y 29 | poke.v(1,spr+6,$0C) # position 11, no flips. 30 | poke.v(1,spr+7,$50) # 64x64 4 colour 31 | } 32 | 33 | const MARIO.COUNT 10 34 | const MARIO.GAP 1 35 | 36 | proc main() { 37 | var n 38 | 39 | print.character($90) 40 | print.character(1) 41 | print.character(147) 42 | 43 | poke.b($9f29,$61) # layer 2 on sprites on 44 | poke.b($9f2a,$40) # double normal scale 45 | poke.b($9f2b,$40) 46 | 47 | load.data("sprites0.bin",0) 48 | 49 | times(16,n) { 50 | poke.v(0,n<<,$2A) 51 | poke.v(0,n<<++,n) 52 | } 53 | 54 | times(MARIO.COUNT,n) { 55 | init.sprite(n << << << + $FC00,n*MARIO.GAP) 56 | } 57 | 58 | halt.program() 59 | var x,xa 60 | while (0 == 0) { 61 | times(MARIO.COUNT,n) { 62 | n << << << + $FC02 -> xa 63 | peek.v(1,xa) -> x 64 | poke.v(1,xa,n & 3 + x ++) 65 | } 66 | x ++ & $FF -> x 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /documents/graphics/graphics/test.prg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/documents/graphics/graphics/test.prg -------------------------------------------------------------------------------- /documents/graphics/scripts/scanner.py: -------------------------------------------------------------------------------- 1 | # ******************************************************************************************* 2 | # ******************************************************************************************* 3 | # 4 | # File: scanner.py 5 | # Date: 13th November 2020 6 | # Purpose: Scans runtime source for command/unary markers. 7 | # Author: Paul Robson (paul@robson.org.uk) 8 | # 9 | # ******************************************************************************************* 10 | # ******************************************************************************************* 11 | 12 | import sys,re,os 13 | 14 | commands = {} 15 | entries = {} 16 | 17 | for root,dirs,files in os.walk(".."+os.sep+"runtime"): 18 | for f in [x for x in files if x.endswith(".asm")]: 19 | for l in [x for x in open(root+os.sep+f).readlines() if x.find(";;") >= 0]: 20 | m = re.match("^(.*?)\\:\\s*\\;\\;\\s+([a-zA-Z]+)\\s+\\$([0-9a-fA-F]+)\\s*$",l) 21 | assert m is not None,"Fails "+l+" in "+f 22 | opcode = int(m.group(3),16) 23 | entry = opcode & 15 if opcode < 0xF0 else (opcode & 15)+16 24 | assert opcode not in commands,"Duplicate "+l+" in "+f 25 | assert entry not in entries,"Duplicate "+l+" in "+f 26 | commands[opcode] = { "mnemonic":m.group(2),"label":m.group(1),"entry":entry,"opcode":opcode } 27 | entries[entry] = commands[opcode] 28 | # 29 | # Create jump table 30 | # 31 | h = open(".."+os.sep+"runtime"+os.sep+"generated"+os.sep+"jumptable.inc","w") 32 | h.write(";\n;\tAutomatically generated\n;\n") 33 | for i in range(0,32): 34 | n = i + 0x80 if i < 16 else i+0xE0 35 | if i not in entries: 36 | h.write("\t.word {0:24} ; ${1:02x} {2}\n".format("OpcodeError",n,"?")) 37 | else: 38 | h.write("\t.word {0:24} ; ${1:02x} {2}\n".format(entries[i]["label"],n,entries[i]["mnemonic"])) 39 | h.close() 40 | # 41 | # Create Runtime Opcode list. 42 | # 43 | h = open(".."+os.sep+"compiler"+os.sep+"runtime.py","w") 44 | h.write("#\n#\tAutomatically generated\n#\n") 45 | h.write("class RTOpcodes(object):\n\tpass\n\n") 46 | h.write("RTOpcodes.JSR = 0x00\n\n") 47 | h.write("RTOpcodes.IMMSHORT = 0x00\n") 48 | h.write("RTOpcodes.IMMLONG = 0x10\n") 49 | h.write("RTOpcodes.VARSHORT = 0x20\n") 50 | h.write("RTOpcodes.VARLONG = 0x30\n") 51 | h.write("RTOpcodes.ABS = 0x40\n\n") 52 | keys = [x for x in entries.keys()] 53 | keys.sort() 54 | for e in keys: 55 | h.write("RTOpcodes.{0} = 0x{1:02x}\n".format(entries[e]["mnemonic"].upper(),entries[e]["opcode"])) 56 | h.close() -------------------------------------------------------------------------------- /documents/mode notes.txt: -------------------------------------------------------------------------------- 1 | 2 | $9F29: (3) 3 | Sprites enable bit (bit 6) 4 | Layer 1 enable bit (bit 5) 5 | Layer 0 enable bit (bit 4) 6 | 7 | $9F2A: H-Scale (4) 8 | $9F29: V-Scale (4) 9 | 4 bits each (00 $80 to 11 $10) 10 | 11 | 12 | Display Config 13 | ============== 14 | Bits 6,5,4 of byte 3 is copied to $9F29 with output mode set. 15 | 16 | If all three are zero then byte 0 specifies a predefined mode looked up from a table. 17 | Mode 0 is the default 80x60 mode. 18 | 19 | Bits 3 and 2 set the VScale ($80 >> n) Bits 1 and 0 the H Scale ($80 >> n) 20 | 21 | Bit 7 and Byte 2 are all set to zero, this is for expansion. 22 | 23 | Lx config (byte 1 is L1,byte 0 is L0) 24 | ===================================== 25 | 26 | [Map Height:2] [Map Width:2] [Tile Size:1] [Bitmap Mode:1] [Colour Depth:2] 27 | 28 | The byte with Tile Size cleared is copied into LX_Config 29 | Map Base address is as default 30 | Tile Base address is as default with the tile size bit copied into bits 0 & 1 31 | Scroll is zeroed. 32 | 33 | L1 default tilebase is $7C (w/h = 0) 34 | L1 map config is $60 35 | 36 | Default Mode 0 37 | 38 | $9F29 = $21 (display config) $20 $00 $60 $00 39 | $9F2A/B = $80 40 | X16VeraLayerConfig = 0 all zeros. 41 | $9F34 = L1_Config = $60 42 | $9F36 = $7C (default value, tile address) 43 | 44 | Switches back to mode 0 if not selected. -------------------------------------------------------------------------------- /documents/review.list: -------------------------------------------------------------------------------- 1 | Review List 2 | =========== 3 | ; 4 | ; Reviewed: 27th April 2021 5 | ; 6 | -------------------------------------------------------------------------------- /documents/test/Makefile: -------------------------------------------------------------------------------- 1 | # ************************************************************************************************ 2 | # ************************************************************************************************ 3 | # 4 | # Name: Makefile 5 | # Purpose: BASIC Program Makefile 6 | # Created: 28th April 2021 7 | # Author: Paul Robson (paul@robsons.org.uk) 8 | # 9 | # ************************************************************************************************ 10 | # ************************************************************************************************ 11 | 12 | ifeq ($(OS),Windows_NT) 13 | include ..\..\documents\general.make 14 | MAKEPRG = copy /y /b $(BINDIR)stub.prg + _basic.tokenised $(APPNAME).prg 15 | else 16 | include ../../documents/general.make 17 | MAKEPRG = cat $(BINDIR)stub.prg _basic.tokenised >$(APPNAME).prg 18 | endif 19 | 20 | ROOTDIR = ..$(S)..$(S) 21 | BINDIR = $(ROOTDIR)bin$(S) 22 | APPNAME = test 23 | 24 | .PHONY: all vram app run 25 | 26 | all : vram app 27 | 28 | vram : data.vram 29 | 30 | data.vram : vram$(S)vram.txt 31 | python $(BINDIR)vramc.zip 32 | 33 | app : $(APPNAME).prg 34 | 35 | $(APPNAME).prg : $(APPNAME).bas 36 | python $(BINDIR)makebasic.zip $(APPNAME).bas 37 | $(MAKEPRG) 38 | 39 | run : app vram 40 | $(EMULATOR) $(APPNAME).prg 41 | -------------------------------------------------------------------------------- /documents/test/_basic.tokenised: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/documents/test/_basic.tokenised -------------------------------------------------------------------------------- /documents/test/data.vram: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/documents/test/data.vram -------------------------------------------------------------------------------- /documents/test/test.bas: -------------------------------------------------------------------------------- 1 | ' 2 | ' "A PET Game I remember from 40 years ago. The idea is to collect" 3 | ' "the numbers on the grid over 60 seconds" 4 | ' 5 | cls 6 | xSize = 32:ySize = 24 7 | proc frame() 8 | dim xc(9),yc(9) 9 | for i = 1 to 9:proc setup(i):next i 10 | xPlayer = xSize/2:yPlayer = ySize/2 11 | proc draw(xPlayer,yPlayer,"*",7) 12 | score = 0:proc draw.score(s+10) 13 | clock = 0:clockEvent = 0:proc draw.clock(clock) 14 | while clock < 60 15 | if event(clockEvent,60) 16 | clock = clock+1:proc draw.clock(clock) 17 | endif 18 | c$ = upper$(chr$(inkey())) 19 | if c$ = "Z" and xPlayer > 0 then proc move(-1,0) 20 | if c$ = "X" and xPlayer < xSize-1 then proc move(1,0) 21 | if c$ = "K" and yPlayer > 0 then proc move(0,-1) 22 | if c$ = "M" and yPlayer < ySize-1 then proc move(0,1) 23 | wend 24 | end 25 | ' 26 | defproc setup(n) 27 | xc(n) = random(xSize) 28 | yc(n) = random(ySize) 29 | proc draw(xc(n),yc(n),chr$(n+48),n mod 6+1) 30 | endproc 31 | ' 32 | defproc draw(x,y,c$,c) 33 | locate x+1,y+2:ink c:print c$; 34 | endproc 35 | ' 36 | defproc frame() 37 | local x,y,a$:ink 6:a$ = "#" 38 | for x = 0 to xSize+1 39 | locate x,1:print a$; 40 | locate x,ySize+2:print a$; 41 | next x 42 | for y = 1 to ySize+2 43 | locate 0,y:print a$; 44 | locate xSize+1,y:print a$; 45 | next 46 | endproc 47 | ' 48 | defproc draw.score(s) 49 | locate 2,0:ink 7:print right$("0000"+str$(s),5) 50 | endproc 51 | ' 52 | defproc draw.clock(c) 53 | local a$:a$ = str$(c) 54 | locate xSize-len(a$),0:ink 7:print a$ 55 | endproc 56 | ' 57 | defproc move(xi,yi) 58 | local i 59 | proc draw(xPlayer,yPlayer," ",7) 60 | xPlayer = xPlayer+xi:yPlayer = yPlayer+yi 61 | proc draw(xPlayer,yPlayer,"*",7) 62 | for i = 1 to 9 63 | if xPlayer = xc(i) and yPlayer = yc(i) 64 | score = score + i 65 | proc draw.score(score) 66 | proc setup(i) 67 | endif 68 | next i 69 | endproc 70 | -------------------------------------------------------------------------------- /documents/test/test.prg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/documents/test/test.prg -------------------------------------------------------------------------------- /documents/test/vram/box.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/documents/test/vram/box.png -------------------------------------------------------------------------------- /documents/test/vram/mario.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/documents/test/vram/mario.png -------------------------------------------------------------------------------- /documents/test/vram/sheet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/documents/test/vram/sheet.png -------------------------------------------------------------------------------- /documents/test/vram/sq_mario.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/documents/test/vram/sq_mario.png -------------------------------------------------------------------------------- /documents/test2/bresenham.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # ***************************************************************************** 3 | # 4 | # Name: bresenham.py 5 | # Purpose: Bresenham type Line Algorithm test 6 | # Created: 1st April 2021 7 | # Author: Paul Robson (paul@robsons.org.uk) 8 | # 9 | # ***************************************************************************** 10 | # ***************************************************************************** 11 | 12 | import random 13 | 14 | # ***************************************************************************** 15 | # 16 | # A simple display class 17 | # 18 | # ***************************************************************************** 19 | 20 | class Display(object): 21 | def __init__(self,width=48,height=32): 22 | self.width = width 23 | self.height = height 24 | self.display = [] 25 | for i in range(0,self.height): 26 | self.display.append(["."] * self.width) 27 | # 28 | def plot(self,x,y,c): 29 | self.display[y][x] = c[0] 30 | # 31 | def show(self): 32 | s = "\n".join(["".join(self.display[x]) for x in range(0,self.height)]) 33 | print(s) 34 | # 35 | def draw(self,x1,y1,x2,y2,c = "*"): 36 | assert x1 <= x2 and y1 <= y2 # only down and left. Sort on Y ; if x1 > x2 then subtract 1. 37 | dx = x2-x1 38 | dy = y1-y2 39 | err = dx + dy 40 | while x1 != x2 or y1 != y2: 41 | self.plot(x1,y1,c) 42 | e2 = 2 * err 43 | if e2 >= dy: 44 | err += dy 45 | x1 += 1 46 | if dx >= e2: 47 | err += dx 48 | y1 += 1 49 | self.plot(x1,y1,c) 50 | 51 | d = Display() 52 | d.draw(2,2,46,12,"A") 53 | d.draw(2,2,16,30,"B") 54 | d.draw(2,2,46,2,"C") 55 | d.draw(2,2,2,30,"D") 56 | d.plot(2,2,"*") 57 | d.show() 58 | 59 | -------------------------------------------------------------------------------- /documents/test2/do.sh: -------------------------------------------------------------------------------- 1 | 64tass -L test.lst -o test.prg test.asm -------------------------------------------------------------------------------- /documents/test2/pages.asm: -------------------------------------------------------------------------------- 1 | 2 | * = $C000 3 | jsr $FEDC 4 | 5 | * = $FFFF 6 | nop 7 | nop 8 | 9 | * = $C000 10 | jsr $BA98 11 | 12 | * = $FFFF 13 | nop 14 | nop 15 | 16 | * = $C000 17 | jsr $7654 18 | 19 | * = $FFFF 20 | nop 21 | -------------------------------------------------------------------------------- /documents/test2/pages.lst: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/documents/test2/pages.lst -------------------------------------------------------------------------------- /documents/test2/test.asm: -------------------------------------------------------------------------------- 1 | 2 | ; 3 | ; Macro test. 4 | ; 5 | 6 | 7 | * = $1000 8 | 9 | editor_delete .macro 10 | lda \1 11 | ldy \2 12 | ldx #len(\@) 13 | jsr Editor 14 | .endm 15 | 16 | 17 | editor_delete #1,#2 18 | editor_delete $04,$05 19 | ;; editor_delete #3 20 | 21 | Editor: 22 | rts 23 | 24 | -------------------------------------------------------------------------------- /documents/test2/test.lst: -------------------------------------------------------------------------------- 1 | 2 | ; 64tass Turbo Assembler Macro V1.55.2200 listing file 3 | ; 64tass -L test.lst -o test.prg test.asm 4 | ; Sat Feb 20 21:21:47 2021 5 | 6 | ;Offset ;Hex ;Monitor ;Source 7 | 8 | ;****** Processing input file: test.asm 9 | 10 | .1000 a9 01 lda #$01 lda #1 11 | .1002 a0 02 ldy #$02 ldy #2 12 | .1004 a2 0d ldx #$0d ldx #13 13 | .1006 20 12 10 jsr $1012 jsr Editor 14 | .1009 a5 04 lda $04 lda $04 15 | .100b a4 05 ldy $05 ldy $05 16 | .100d a2 0d ldx #$0d ldx #13 17 | .100f 20 12 10 jsr $1012 jsr Editor 18 | .1012 Editor: 19 | .1012 60 rts rts 20 | 21 | ;****** End of listing 22 | -------------------------------------------------------------------------------- /documents/test2/test.prg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/documents/test2/test.prg -------------------------------------------------------------------------------- /documents/vram.txt: -------------------------------------------------------------------------------- 1 | VRAM Data File Format 2 | ===================== 3 | 4 | 2 byte header (dummy) 5 | 6 | 00000xxx xxxxxxxx 2 byte instruction, sets the write address to x x 64. 7 | 8 | 00001nnn Set decompression type to nnn. 9 | 10 | 00001111 Palette definition. Next byte is palette index, followed by two byte 11 | colour in Vera Format. This changes the write address, so should be either first 12 | or last. 13 | 14 | 001bhhww nnnnnnnn Define sprite data image n as being here (aligned to 32 bytes automatically) 15 | wwhh is size (as defined in Vera docs) 16 | b is the mode bit (0 = 4 bit,1 = 8 bit.) 17 | 4 bit sprites are expected to use the standard palette (240-255) 18 | 8 bit sprites obviously use the whole palette. 19 | 20 | 10000000 End of data. 21 | 22 | Compression Model 0 (uncompressed) 23 | ================================== 24 | 1nnnnnnn Block of data size n bytes follows. 25 | 26 | 27 | Compression Model 1 (Simple RLE compression) 28 | ============================================ 29 | 10nnnnnn Followed by n bytes of data 30 | 11cccccc Followed by cccccc copies of the following byte. 31 | 32 | -------------------------------------------------------------------------------- /programs/grabber/Makefile: -------------------------------------------------------------------------------- 1 | # ************************************************************************************************ 2 | # ************************************************************************************************ 3 | # 4 | # Name: Makefile 5 | # Purpose: BASIC Program Makefile 6 | # Created: 28th April 2021 7 | # Author: Paul Robson (paul@robsons.org.uk) 8 | # 9 | # ************************************************************************************************ 10 | # ************************************************************************************************ 11 | 12 | ifeq ($(OS),Windows_NT) 13 | include ..\..\documents\general.make 14 | MAKEPRG = copy /y /b $(BINDIR)stub.prg + _basic.tokenised $(APPNAME).prg 15 | else 16 | include ../../documents/general.make 17 | MAKEPRG = cat $(BINDIR)stub.prg _basic.tokenised >$(APPNAME).prg 18 | endif 19 | 20 | ROOTDIR = ..$(S)..$(S) 21 | BINDIR = $(ROOTDIR)bin$(S) 22 | APPNAME = grabber 23 | 24 | .PHONY: all vram app run 25 | 26 | all : vram app 27 | 28 | vram : data.vram 29 | 30 | data.vram : vram$(S)vram.txt 31 | python $(BINDIR)vramc.zip 32 | 33 | app : $(APPNAME).prg 34 | 35 | $(APPNAME).prg : $(APPNAME).bas 36 | python $(BINDIR)makebasic.zip $(APPNAME).bas 37 | $(MAKEPRG) 38 | 39 | run : app vram 40 | $(EMULATOR) $(APPNAME).prg 41 | -------------------------------------------------------------------------------- /programs/grabber/_basic.tokenised: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/programs/grabber/_basic.tokenised -------------------------------------------------------------------------------- /programs/grabber/data.vram: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/programs/grabber/data.vram -------------------------------------------------------------------------------- /programs/grabber/dump.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/programs/grabber/dump.bin -------------------------------------------------------------------------------- /programs/grabber/grabber.prg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/programs/grabber/grabber.prg -------------------------------------------------------------------------------- /programs/grabber/vram/vram.txt: -------------------------------------------------------------------------------- 1 | ; 2 | ; Empty , generates a two byte file you can ignore. 3 | ; -------------------------------------------------------------------------------- /programs/pong/Makefile: -------------------------------------------------------------------------------- 1 | # ************************************************************************************************ 2 | # ************************************************************************************************ 3 | # 4 | # Name: Makefile 5 | # Purpose: BASIC Program Makefile 6 | # Created: 28th April 2021 7 | # Author: Paul Robson (paul@robsons.org.uk) 8 | # 9 | # ************************************************************************************************ 10 | # ************************************************************************************************ 11 | 12 | ifeq ($(OS),Windows_NT) 13 | include ..\..\documents\general.make 14 | MAKEPRG = copy /y /b $(BINDIR)stub.prg + _basic.tokenised $(APPNAME).prg 15 | else 16 | include ../../documents/general.make 17 | MAKEPRG = cat $(BINDIR)stub.prg _basic.tokenised >$(APPNAME).prg 18 | endif 19 | 20 | ROOTDIR = ..$(S)..$(S) 21 | BINDIR = $(ROOTDIR)bin$(S) 22 | APPNAME = pong 23 | 24 | .PHONY: all vram app run 25 | 26 | all : vram app 27 | 28 | vram : data.vram 29 | 30 | data.vram : vram$(S)vram.txt 31 | python $(BINDIR)vramc.zip 32 | 33 | app : $(APPNAME).prg 34 | 35 | $(APPNAME).prg : $(APPNAME).bas 36 | python $(BINDIR)makebasic.zip $(APPNAME).bas 37 | $(MAKEPRG) 38 | 39 | run : app vram 40 | $(EMULATOR) $(APPNAME).prg 41 | -------------------------------------------------------------------------------- /programs/pong/_basic.tokenised: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/programs/pong/_basic.tokenised -------------------------------------------------------------------------------- /programs/pong/data.vram: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/programs/pong/data.vram -------------------------------------------------------------------------------- /programs/pong/dump.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/programs/pong/dump.bin -------------------------------------------------------------------------------- /programs/pong/pong.prg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/programs/pong/pong.prg -------------------------------------------------------------------------------- /programs/pong/vram/ball.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/programs/pong/vram/ball.png -------------------------------------------------------------------------------- /programs/pong/vram/bat1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/programs/pong/vram/bat1.png -------------------------------------------------------------------------------- /programs/pong/vram/bat2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/programs/pong/vram/bat2.png -------------------------------------------------------------------------------- /programs/pong/vram/vram.txt: -------------------------------------------------------------------------------- 1 | MOVE $4000 2 | COLOUR sprite 3 | SPRITE 0,8,8 4 | IMAGE ball.png 5 | SPRITE 1,8,16 6 | IMAGE bat1.png 7 | SPRITE 2,8,32 8 | IMAGE bat2.png 9 | -------------------------------------------------------------------------------- /scripts/__pycache__/tokeniser.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/scripts/__pycache__/tokeniser.cpython-39.pyc -------------------------------------------------------------------------------- /scripts/__pycache__/tokens.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/scripts/__pycache__/tokens.cpython-39.pyc -------------------------------------------------------------------------------- /scripts/build/__main__.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # ***************************************************************************** 3 | # 4 | # Name: __main__.py 5 | # Author: Paul Robson (paul@robsons.org.uk) 6 | # Date: 11th March 2021 7 | # Purpose: Main program for zipped makebasic.zip app. 8 | # 9 | # ***************************************************************************** 10 | # ***************************************************************************** 11 | 12 | import os,re,sys 13 | from tokeniser import * 14 | from tokens import * 15 | from makepgm import * 16 | 17 | pb = ProgramBuilder() 18 | if len(sys.argv) == 1: 19 | print("python makebasic.zip ") 20 | else: 21 | for f in sys.argv[1:]: 22 | pb.load(f) 23 | pb.exportBin("_basic.tokenised".replace("/",os.sep)) 24 | -------------------------------------------------------------------------------- /scripts/build/__pycache__/asmdata.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/scripts/build/__pycache__/asmdata.cpython-39.pyc -------------------------------------------------------------------------------- /scripts/build/__pycache__/tokendata.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/scripts/build/__pycache__/tokendata.cpython-39.pyc -------------------------------------------------------------------------------- /scripts/build/__pycache__/tokeniser.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/scripts/build/__pycache__/tokeniser.cpython-39.pyc -------------------------------------------------------------------------------- /scripts/build/__pycache__/tokens.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/scripts/build/__pycache__/tokens.cpython-39.pyc -------------------------------------------------------------------------------- /scripts/build/asmtables.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # ***************************************************************************** 3 | # 4 | # Name: asmtables.py 5 | # Author: Paul Robson (paul@robsons.org.uk) 6 | # Date: 13th March 2021 7 | # Purpose: Generate various tables (assembler specific) 8 | # 9 | # ***************************************************************************** 10 | # ***************************************************************************** 11 | 12 | from tokens import * 13 | import os,re,sys 14 | 15 | t = Tokens() 16 | header= ";\n;\tAutomatically generated\n;\n" # header used. 17 | genDir = "../source/generated/".replace("/",os.sep) 18 | # 19 | groupStart = [ 0 ] * 6 20 | n = t.getBaseAsmToken() 21 | while t.getFromID(1,n) is not None: 22 | info = t.getAsmInfo(t.getFromID(1,n)["token"]) 23 | lvl = int(info[2]) 24 | if groupStart[lvl] == 0: 25 | groupStart[lvl] = n 26 | n = n + 1 27 | groupStart[5] = n 28 | # 29 | # Create the constants table. 30 | # 31 | h = open(genDir+"asmconst.inc","w") 32 | h.write(header) 33 | for i in range(1,5): 34 | h.write("TKA_GROUP{0} = ${1:02x}\n".format(i,groupStart[i])) 35 | h.write("TKA_END4 = ${0:02x}\n\n".format(groupStart[5] )) 36 | h.close() 37 | # 38 | # Create the data tables for assembler. 39 | # 40 | h = open(genDir+"asmtables.inc","w") 41 | h.write(header) 42 | # 43 | # Token ID to Opcode 44 | # 45 | h.write("OpcodeTable:\n") 46 | for i in range(groupStart[1],groupStart[5]): 47 | m = t.getFromID(1,i) 48 | opcode = int(t.getAsmInfo(m["token"])[0],16) 49 | h.write("\t.byte\t${0:02x}\t\t\t; ${1:02x} {2}\n".format(opcode,i,m["token"].lower())) 50 | h.write("\n") 51 | # 52 | # Group 2 Usage 53 | # 54 | h.write("Group2OpcodeAvailability:\n") 55 | for i in range(groupStart[2],groupStart[3]): 56 | m = t.getFromID(1,i) 57 | info = t.getAsmInfo(m["token"]) 58 | opcode = int(info[0],16) 59 | bitMask = 0 60 | for b in range(0,8): 61 | if info[b+3] != "": 62 | bitMask += (1 << b) 63 | h.write("\t.byte\t${0:02x}\t\t\t; ${1:02x} {2} ${3:02x}\n".format(bitMask,i,m["token"].lower(),opcode)) 64 | h.write("\n") 65 | # 66 | # Special cases (token,mode,opcode), ends with token 0 67 | # 68 | h.write("AssemblerSpecialCases:\n") 69 | for c in t.getAsmSpecialCases(): 70 | token = t.getFromToken(c[1]) 71 | h.write("\t.byte\t${1:02x},{2},${0:02x}\t\t; {3} {4}\n".format(int(c[0],16),token["id"],c[3],c[1],c[4])) 72 | h.write("\t.byte\t0\n") 73 | h.close() 74 | -------------------------------------------------------------------------------- /scripts/build/errorgen.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # ***************************************************************************** 3 | # 4 | # Name: errorgen.py 5 | # Author: Paul Robson (paul@robsons.org.uk) 6 | # Date: 21st February 2021 7 | # Purpose: Generates error list and includes. 8 | # 9 | # ***************************************************************************** 10 | # ***************************************************************************** 11 | 12 | import re,os,sys 13 | 14 | languageFile = "english.txt" 15 | 16 | errorDef = open("../scripts/languages/"+languageFile).readlines() # Load error file 17 | errorDef = [x.strip() for x in errorDef if x.strip() != ""] 18 | errorDef = [x.replace("\t"," ") for x in errorDef if not x.startswith(";")] 19 | 20 | genDir = "../source/generated/".replace("/",os.sep) 21 | header = ";\n;\tAutomatically generated\n;\n" # header used. 22 | 23 | errors = [] 24 | errID = 1 25 | 26 | for s in errorDef: 27 | s = s.split(":") 28 | s = s if len(s) == 2 else s + s 29 | errors.append({ "ID":errID,"Label":s[0],"Text":s[1] }) 30 | errID += 1 31 | 32 | # 33 | # Create list of error IDs. 34 | # 35 | h = open(genDir+"errorid.inc","w") 36 | h.write(header) 37 | for e in errors: 38 | h.write("ErrorID_{1} = {0} ; {2}\n".format(e["ID"],e["Label"],e["Text"])) 39 | h.close() 40 | # 41 | # Create list of length-prefix error texts. 42 | # 43 | h = open(genDir+"errortext.inc","w") 44 | h.write(header) 45 | h.write("ErrorTextList:\n") 46 | for e in errors: 47 | h.write('\t.text {1},"{0}"\n'.format(e["Text"],len(e["Text"]))) 48 | h.write("\t.byte 0\n\n") 49 | h.close() 50 | -------------------------------------------------------------------------------- /scripts/build/tokendata.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # ***************************************************************************** 3 | # 4 | # Name: tokendata.py 5 | # Author: Paul Robson (paul@robsons.org.uk) 6 | # Date: 3rd April 2021 7 | # Purpose: Token class 8 | # 9 | # ***************************************************************************** 10 | # ***************************************************************************** 11 | 12 | import re,os,sys 13 | 14 | # ***************************************************************************** 15 | # 16 | # Tokens : Raw Data as a Python Class 17 | # 18 | # ***************************************************************************** 19 | 20 | class TokenData(object): 21 | # 22 | # Tokens Source. Currently done by hand. 23 | # 24 | def getSource(self): 25 | return """ 26 | ## 27 | ## Binary operators, must be first. 28 | ## 29 | [1] and or xor 30 | [2] >= <= > < = <> 31 | [3] + - 32 | [4] >> << * / mod 33 | [5] ^ 34 | [6] ! ? 35 | ## 36 | ## Operators that effect the structure depth follow. 37 | [+] 38 | repeat while for if defproc 39 | [-] 40 | until wend next then endif endproc 41 | ## 42 | ## 43 | ## Then unary functions follow (not floating point ones.) 44 | ## 45 | [unary] 46 | ( 47 | len( sgn( abs( random( page 48 | true false min( max( sys( 49 | timer( event( get( inkey( alloc( 50 | chr$( left$( mid$( right$( str$( 51 | val( peek( deek( leek( asc( 52 | int( float( isval( upper$( lower$( 53 | @ ~ & get$( inkey$( 54 | mem 55 | ## 56 | ## Then command and syntax and so on. 57 | ## 58 | [command] 59 | ) : , ; ' 60 | to step proc local dim 61 | rem let input else vdu 62 | print data image at flip 63 | assert poke doke loke ink 64 | paper cls locate . from 65 | # clear text type time 66 | ## 67 | ## Put these in group 1. 68 | ## 69 | [group1] 70 | load save list new break 71 | run read restore end stop 72 | xemu goto gosub return 73 | ## 74 | ## System specific commands in group 2 75 | ## 76 | [group2] 77 | vpoke vdoke vload mode palette 78 | sprite clg rect frame draw 79 | plot line paint sound 80 | ## 81 | ## Floating point functions and system unary functions in group 3. 82 | ## 83 | [group3] 84 | vpeek( vdeek( sprite.x( sprite.y( 85 | hit( joy.x( joy.y( joy.b( 86 | clock( playing( 87 | """ 88 | -------------------------------------------------------------------------------- /scripts/languages/english.txt: -------------------------------------------------------------------------------- 1 | ; ***************************************************************************** 2 | ; ***************************************************************************** 3 | ; 4 | ; Name: english.txt 5 | ; Author: Paul Robson (paul@robsonsorguk) 6 | ; Created: 11th March 2021 7 | ; Purpose: English language error messages 8 | ; 9 | ; ***************************************************************************** 10 | ; ***************************************************************************** 11 | 12 | ; 13 | ; Syntax Error, name : text (default text is name) 14 | ; 15 | ; Called with Error macro eg Error BadType 16 | ; 17 | 18 | Missing:Feature not Present 19 | Syntax:Syntax Error 20 | NoModule:Module disabled 21 | Assert:Assertion failed 22 | DivZero:Divide By Zero 23 | Stop 24 | BadType:Type Mismatch 25 | BadValue:Illegal Value 26 | MissingRP:Missing right bracket 27 | MissingComma:Missing comma 28 | NoReference:Missing reference 29 | LineNumber:Line Number not found 30 | StrLen:String too long 31 | ReturnErr:RETURN without GOSUB 32 | UntilErr:UNTIL without REPEAT 33 | NextErr:NEXT without FOR 34 | WendErr:WEND without WHILE 35 | endprocErr:ENDPROC without PROC 36 | BadIndex:Bad NEXT index 37 | Struct:Structures nested wrong 38 | NoAuto:Cannot create variable 39 | RetStack:Return stack out of space 40 | NoProc:Unknown Procedure 41 | Params:Parameters do not match 42 | DupArray:Array already defined 43 | NotArray:DIM requires array 44 | ArrayIndex:Bad array index 45 | ArrayDepth:Wrong number of array indices 46 | DataError:Out of data 47 | Tokenise:Cannot tokenise line 48 | Save:Save failed 49 | Load:Load failed 50 | Break:Break 51 | Memory:Out of memory 52 | NumStack:Expression too complex 53 | Assembler:Bad Operand/Mode 54 | Branch:Branch out of range 55 | Label:Label changed value 56 | NoSprite:No Sprite Selected 57 | Hardware:Hardware 58 | NoGfx:No graphics available -------------------------------------------------------------------------------- /scripts/miscellaneous/analyse.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # ***************************************************************************** 3 | # 4 | # Name: usage.py 5 | # Author: Paul Robson (paul@robsons.org.uk) 6 | # Date: 27th February 2021 7 | # Purpose: Analyse usage of program. 8 | # 9 | # ***************************************************************************** 10 | # ***************************************************************************** 11 | 12 | import os,re,sys 13 | 14 | segments = {} 15 | total = 0 16 | 17 | if len(sys.argv) == 2: 18 | for l in open(sys.argv[1]).readlines(): 19 | if l.startswith("section_"): 20 | m = re.match("^section_([a-z]+)_(.*?)\\s*\\=\\s*\\$([0-9a-f]+)\\s*$",l.lower()) 21 | segment = m.group(2) 22 | if segment not in segments: 23 | segments[segment] = {} 24 | segments[segment][m.group(1).strip()] = int(m.group(3),16) 25 | keys = [x for x in segments.keys()] 26 | keys.sort(key = lambda x:segments[x]["start"]) 27 | for k in keys: 28 | sz = segments[k]["end"]-segments[k]["start"] 29 | total += sz 30 | print("Section {0:16} ${1:04x}-${2:04x} ({3} bytes)".format('"'+k+'"',segments[k]["start"],segments[k]["end"],sz)) 31 | print("\nApproximate total {0} bytes.".format(total)) -------------------------------------------------------------------------------- /scripts/miscellaneous/callcheck.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # ***************************************************************************** 3 | # 4 | # Name: callcheck.py 5 | # Author: Paul Robson (paul@robsons.org.uk) 6 | # Date: 9th March 2021 7 | # Purpose: Checks all calls are internal, i.e. the code doesn't 8 | # jmp or jsr to a routine in another module. 9 | # 10 | # ***************************************************************************** 11 | # ***************************************************************************** 12 | 13 | import re,os,sys 14 | 15 | sections = {} 16 | 17 | for root,dirs,files in os.walk("../source"): 18 | section = root.split("/") 19 | if len(section) > 2: 20 | section = section[2] 21 | if section not in sections: 22 | sections[section] = { "targets":{},"labels":{} } 23 | for f in [x for x in files if x.endswith(".asm")]: 24 | for l in open(root+os.sep+f).readlines(): 25 | if l.find(":") > 0: 26 | m = re.match("^([0-9A-Za-z\\_]+)\\:",l) 27 | if m is not None: 28 | sections[section]["labels"][m.group(1).lower().strip()] = True 29 | if l.find("jsr") >= 0 or l.find ("jmp") >= 0: 30 | m = re.search("jsr\\s+([0-9A-Za-z\\_]+)",l) 31 | if m is None: 32 | m = re.search("jmp\\s+([0-9A-Za-z\\_]+)",l) 33 | if m is not None: 34 | sections[section]["targets"][m.group(1).lower().strip()] = True 35 | 36 | secKeys = [x for x in sections.keys()] 37 | secKeys.sort() 38 | for k in secKeys: 39 | for t in sections[k]["targets"].keys(): 40 | if t not in sections[k]["labels"] and t != "initialiseall": 41 | print("Bad : "+t+" accessed in "+k) 42 | -------------------------------------------------------------------------------- /scripts/miscellaneous/revcheck.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # ***************************************************************************** 3 | # 4 | # Name: revcheck.py 5 | # Author: Paul Robson (paul@robsons.org.uk) 6 | # Date: 11th March 2021 7 | # Purpose: Scan for review checks. 8 | # 9 | # ***************************************************************************** 10 | # ***************************************************************************** 11 | 12 | import re,os,sys 13 | 14 | months = { "JAN":1,"FEB":2,"MAR":3,"APR":4,"MAY":5,"JUN":6,"JUL":7,"AUG":8,"SEP":9,"OCT":10,"NOV:":11,"DEC":12 } 15 | 16 | def toDate(s): 17 | m = re.match("^(\\d+)[A-Z]+\\s*(\\w+)\\s*(\\d+)$",s.strip().upper()) 18 | assert m is not None,"Bad date ["+s.strip().upper()+"]" 19 | mn = months[m.group(2)[:3]] 20 | date = [int(m.group(1)),mn,int(m.group(3))] 21 | return date 22 | 23 | sources = {} 24 | 25 | for root,dirs,files in os.walk("../source"): 26 | for f in [x for x in files if x.endswith(".asm") or x.endswith(".inc")]: 27 | #print(f) 28 | info = { "create":None,"review":None } 29 | isAuto = False 30 | for l in open(root+os.sep+f).readlines(): 31 | if l.startswith(";"): 32 | if l.find("Automatically generated") >= 0: 33 | isAuto = True 34 | if l.find("Created:") >= 0: 35 | m = re.match("^\\;.*?\\:(.*)$",l) 36 | info["create"] = toDate(m.group(1)) 37 | if l.find("Reviewed:") >= 0: 38 | m = re.match("^\\;.*?\\:(.*)$",l) 39 | info["review"] = toDate(m.group(1)) 40 | if not isAuto: 41 | sources[root+os.sep+f] = info 42 | 43 | for s in sources: 44 | if sources[s]["review"] is None: 45 | print(s,sources[s]["create"]) 46 | 47 | -------------------------------------------------------------------------------- /scripts/miscellaneous/testvram.py: -------------------------------------------------------------------------------- 1 | # 2 | # Produce test RAM file, quick bodge for development. PSR 22/3/2021 3 | # 4 | def add(data,text,x,y,colour): 5 | pos = x * 64 + y * 256 6 | assert (pos & 63) == 0 7 | pos = pos >> 6 8 | data.append(pos >> 8) # position 9 | data.append(pos & 0xFF) 10 | data.append(128+len(text)*2) # block of len(text)x2 characters/attributes 11 | for c in text: 12 | data.append(ord(c)) 13 | data.append(colour) 14 | 15 | fileData = [0,0,0x08] # at 0,0, comrpession 0 16 | 17 | 18 | fileData.append(0x0F) # colour 2 to $F80 (orange) 19 | fileData.append(0xF3) 20 | fileData.append(0x80) 21 | fileData.append(0x0F) 22 | 23 | 24 | add(fileData,"Hemmo world!",1,0,4) 25 | #add(fileData,"Hexxo world!",2,2,5) 26 | #add(fileData,"Heyyo world!",0,3,6) 27 | 28 | vrStart = 64*256 29 | vrStart = int(vrStart/64) 30 | fileData.append(vrStart >> 8) 31 | fileData.append(vrStart & 0xFF) 32 | 33 | fileData.append(0x25) # 0010 0101 => Size 16x16 sprite, 4 bpp. 34 | fileData.append(2) 35 | fileData.append(0xFF) # 127 bytes of data, fake sprite. 36 | for i in range(0,127): 37 | fileData.append(0x22 if i%8 == 4 else 0x33) 38 | 39 | fileData.append(0x25) # 0010 0101 => Size 16x16 sprite, 4 bpp. 40 | fileData.append(3) 41 | fileData.append(0xFF) # 127 bytes of data, fake sprite. 42 | for i in range(0,127): 43 | fileData.append(0x00 if (i >> 3)%8 == 2 or i%8 == 1 else 0x33) 44 | 45 | 46 | fileData.append(0x80) 47 | 48 | fileData = [0xDD,0xDD] + fileData # add dummy marker. 49 | 50 | 51 | h = open("test.vram","wb") 52 | h.write(bytes(fileData)) 53 | h.close() 54 | -------------------------------------------------------------------------------- /scripts/tests/__pycache__/testcore.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/scripts/tests/__pycache__/testcore.cpython-39.pyc -------------------------------------------------------------------------------- /scripts/tests/__pycache__/tokeniser.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/scripts/tests/__pycache__/tokeniser.cpython-39.pyc -------------------------------------------------------------------------------- /scripts/tests/testarr.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # ***************************************************************************** 3 | # 4 | # Name: testarr.py 5 | # Author: Paul Robson (paul@robsons.org.uk) 6 | # Date: 7th March 2021 7 | # Purpose: Test arrays(single dimension) 8 | # 9 | # ***************************************************************************** 10 | # ***************************************************************************** 11 | 12 | import random,sys 13 | from testcore import * 14 | 15 | class ArrayTest(Test): 16 | 17 | def prefixCode(self,h): 18 | self.current = {} 19 | for i in range(1,20): 20 | name = "".join([chr(random.randint(97,117)) for c in range(0,random.randint(1,5))]) 21 | if len(name) > 1: 22 | name = name[0]+"0"+name[1:] 23 | if i % 2 == 0: 24 | name = name + "$" 25 | name += "(" 26 | size = random.randint(1,9) 27 | if name not in self.current: 28 | self.current[name] = [ None ] * size 29 | h.write("dim {0}{1})\n".format(name,size)) 30 | self.names = [x for x in self.current.keys()] 31 | 32 | def getTest(self,n): 33 | var = self.names[random.randint(0,len(self.names)-1)] 34 | index = random.randint(0,len(self.current[var])-1) 35 | value = str(random.randint(0,999)) 36 | if var.find("$") >= 0: 37 | value = '"'+"".join([chr(random.randint(65,85)) for s in range(0,random.randint(0,7))])+'"' 38 | self.current[var][index] = value 39 | return "{0}{2}) = {1}".format(var,value,index) 40 | 41 | def postfixCode(self,h): 42 | for n in self.names: 43 | for i in range(0,len(self.current[n])): 44 | if self.current[n][i] is not None: 45 | h.write("assert {0}{2}) = {1}\n".format(n,self.current[n][i],i)) 46 | 47 | if __name__ == "__main__": 48 | t = ArrayTest(500) 49 | -------------------------------------------------------------------------------- /scripts/tests/testarr2.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # ***************************************************************************** 3 | # 4 | # Name: testarr2.py 5 | # Author: Paul Robson (paul@robsons.org.uk) 6 | # Date: 7th March 2021 7 | # Purpose: Test arrays(multi dimension) 8 | # 9 | # ***************************************************************************** 10 | # ***************************************************************************** 11 | 12 | import random,sys 13 | from testcore import * 14 | 15 | class ArrayTest(Test): 16 | 17 | def prefixCode(self,h): 18 | self.current = {} 19 | self.firstDim = {} 20 | self.access = {} 21 | for i in range(1,20): 22 | name = "".join([chr(random.randint(97,117)) for c in range(0,random.randint(1,5))]) 23 | if len(name) > 1: 24 | name = name[0]+"0"+name[1:] 25 | if i % 2 == 0: 26 | name = name + "$" 27 | name += "(" 28 | size = random.randint(1,9) 29 | if name not in self.current: 30 | self.current[name] = [ None ] * size 31 | self.firstDim[name] = random.randint(1,4) 32 | self.access[name] = random.randint(0,self.firstDim[name]) 33 | h.write("dim {0}{2},{1})\n".format(name,size,self.firstDim[name])) 34 | self.names = [x for x in self.current.keys()] 35 | 36 | def getTest(self,n): 37 | var = self.names[random.randint(0,len(self.names)-1)] 38 | index = random.randint(0,len(self.current[var])-1) 39 | value = str(random.randint(0,999)) 40 | if var.find("$") >= 0: 41 | value = '"'+"".join([chr(random.randint(65,85)) for s in range(0,random.randint(0,7))])+'"' 42 | self.current[var][index] = value 43 | return "{0}{3},{2}) = {1}".format(var,value,index,self.access[var]) 44 | 45 | def postfixCode(self,h): 46 | for n in self.names: 47 | for i in range(0,len(self.current[n])): 48 | if self.current[n][i] is not None: 49 | h.write("assert {0}{3},{2}) = {1}\n".format(n,self.current[n][i],i,self.access[n])) 50 | 51 | if __name__ == "__main__": 52 | t = ArrayTest(5) 53 | -------------------------------------------------------------------------------- /scripts/tests/testbin.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # ***************************************************************************** 3 | # 4 | # Name: testbin.py 5 | # Author: Paul Robson (paul@robsons.org.uk) 6 | # Date: 26th February 2021 7 | # Purpose: Binary test classes. 8 | # 9 | # ***************************************************************************** 10 | # ***************************************************************************** 11 | 12 | import random,sys 13 | from testcore import * 14 | 15 | # ***************************************************************************** 16 | # 17 | # Integer Binary operator test 18 | # 19 | # + - * / mod 20 | # and or xor << >> 21 | # comparisons 22 | # 23 | # ***************************************************************************** 24 | 25 | class BinopTest(Test): 26 | def getTest(self,n): 27 | ok = False 28 | while not ok: 29 | op = "+ - * / % & | ^ < = > <= >= <> >> <<".split(" ") 30 | op = op[random.randint(0,len(op)-1)] 31 | opn = op 32 | n1 = random.randint(-10000000,10000000) 33 | n2 = random.randint(-10000000,10000000) 34 | n3 = 0 35 | if "%".find(op) >= 0: 36 | n1 = abs(n1) 37 | n2 = abs(n2) 38 | if op == "+": 39 | n3 = n1 + n2 40 | if op == "-": 41 | n3 = n1 - n2 42 | if op == "*": 43 | n3 = n1 * n2 44 | if op == "/": 45 | n3 = abs(n1) // abs(n2) 46 | if n1 * n2 < 0: 47 | n3 = -n3 48 | if op == "%": 49 | opn = "mod" 50 | n3 = n1 % n2 51 | if op == "&": 52 | opn = "and" 53 | n3 = n1 & n2 54 | if op == "|": 55 | opn = "or" 56 | n3 = n1 | n2 57 | if op == "^": 58 | opn = "xor" 59 | n3 = n1 ^ n2 60 | if op == ">>": 61 | n1 = abs(n1) 62 | n2 = n2 & 31 63 | n3 = n1 >> n2 64 | if op == "<<": 65 | n1 = abs(n1) 66 | n2 = n2 & 31 67 | n3 = n1 << n2 68 | if op == ">": 69 | n3 = -1 if n1 > n2 else 0 70 | if op == "<": 71 | n3 = -1 if n1 < n2 else 0 72 | if op == "=": 73 | n3 = -1 if n1 == n2 else 0 74 | if op == ">=": 75 | n3 = -1 if n1 >= n2 else 0 76 | if op == "<=": 77 | n3 = -1 if n1 <= n2 else 0 78 | if op == "<>": 79 | n3 = -1 if n1 != n2 else 0 80 | 81 | ok = n3 >= -0x80000000 and n3 < 0x7FFFFFFF 82 | return "assert ({0} {1} {2}) = {3}".format(n1,opn,n2,n3) 83 | 84 | if __name__ == "__main__": 85 | t = BinopTest(500) 86 | -------------------------------------------------------------------------------- /scripts/tests/testcore.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # ***************************************************************************** 3 | # 4 | # Name: testcore.py 5 | # Author: Paul Robson (paul@robsons.org.uk) 6 | # Date: 26th February 2021 7 | # Purpose: Core test classes. 8 | # 9 | # ***************************************************************************** 10 | # ***************************************************************************** 11 | 12 | import random,sys 13 | 14 | # ***************************************************************************** 15 | # 16 | # Base test class 17 | # 18 | # ***************************************************************************** 19 | 20 | class Test(object): 21 | # 22 | # Create test. 23 | # 24 | def __init__(self,count=100): 25 | random.seed() 26 | self.seed = random.randint(10000,99999) 27 | #self.seed = 35538 28 | random.seed(self.seed) 29 | h = sys.stdout 30 | self.prefixCode(h) 31 | h.write(";\n;\tBuilt using seed {0}\n;\n".format(self.seed)) 32 | for i in range(0,count): 33 | h.write("{0}\n".format(self.getTest(i))) 34 | self.postfixCode(h) 35 | h.write("xemu\n") 36 | # 37 | # Dummy test 38 | # 39 | def getTest(self,n): 40 | return "assert 1" 41 | # 42 | # Dummy prefix/postfix 43 | # 44 | def prefixCode(self,h): 45 | pass 46 | def postfixCode(self,h): 47 | pass 48 | 49 | if __name__ == "__main__": 50 | t = Test(500) 51 | -------------------------------------------------------------------------------- /scripts/tests/testprec.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # ***************************************************************************** 3 | # 4 | # Name: testprec.py 5 | # Author: Paul Robson (paul@robsons.org.uk) 6 | # Date: 27th February 2021 7 | # Purpose: Precedence test classes. 8 | # 9 | # ***************************************************************************** 10 | # ***************************************************************************** 11 | 12 | import random,sys 13 | from testcore import * 14 | 15 | # ***************************************************************************** 16 | # 17 | # Precedence test 18 | # 19 | # ***************************************************************************** 20 | 21 | class PrecedenceTest(Test): 22 | def getTest(self,n): 23 | expr = self.term(3) 24 | return "assert ({0}) = {1}".format(expr,eval(expr)) 25 | # 26 | def term(self,n): 27 | if n == 0 or random.randint(0,4) == 0: 28 | return str(random.randint(2,5)) 29 | t = "+".join([self.term(n-1) for s in range (0,random.randint(1,3))]) 30 | t = [x for x in t] 31 | for i in range(0,len(t)): 32 | if t[i] == "+": 33 | t[i] = "+-*"[random.randint(0,2)] 34 | t = "".join(t) 35 | return t if random.randint(0,1) == 0 else "("+t+")" 36 | # 37 | if __name__ == "__main__": 38 | t = PrecedenceTest(100) 39 | -------------------------------------------------------------------------------- /scripts/tests/teststr.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # ***************************************************************************** 3 | # 4 | # Name: teststr.py 5 | # Author: Paul Robson (paul@robsons.org.uk) 6 | # Date: 3rd March 2021 7 | # Purpose: String mani.pulation tests 8 | # 9 | # ***************************************************************************** 10 | # ***************************************************************************** 11 | 12 | import random,sys 13 | from testcore import * 14 | 15 | class StringTest(Test): 16 | 17 | def prefixCode(self,h): 18 | self.current = {} 19 | for i in range(0,30): 20 | name = "".join([chr(random.randint(97,117)) for c in range(0,random.randint(1,5))]) 21 | name = name + "$" 22 | self.current[name] = self.getValue(0,4) 23 | self.current[name] = "" 24 | h.write("{0} = \"{1}\"+\"\"\n".format(name,self.current[name])) 25 | self.names = [x for x in self.current.keys()] 26 | 27 | def getTest(self,n): 28 | v1 = self.names[random.randint(0,len(self.names)-1)] 29 | v2 = self.names[random.randint(0,len(self.names)-1)] 30 | # 31 | n = random.randint(0,4) 32 | if n == 0: 33 | self.current[v1] = "" 34 | return v1+' = ""' 35 | 36 | if n == 1: 37 | self.current[v1] = self.getValue(1,5) 38 | return '{0} = "{1}"'.format(v1,self.current[v1]) 39 | 40 | if n == 2: 41 | av = self.getValue(1,5) 42 | if len(self.current[v1])+len(av) < 240: 43 | self.current[v1] += av 44 | return '{0} = {0} + "{1}"'.format(v1,av) 45 | 46 | if n == 3: 47 | if len(self.current[v1])+len(self.current[v2]) < 240: 48 | self.current[v1] += self.current[v2] 49 | return '{0} = {0} + {1}'.format(v1,v2) 50 | 51 | if n == 4: 52 | self.current[v1] = self.current[v2] 53 | return '{0} = {1}'.format(v1,v2) 54 | 55 | return "rem" 56 | 57 | def postfixCode(self,h): 58 | for n in self.names: 59 | h.write("assert {0} = \"{1}\"\n".format(n,self.current[n])) 60 | 61 | def getValue(self,l1,l2): 62 | return "".join([chr(random.randint(65,85)) for c in range(0,random.randint(l1,l2))]) 63 | 64 | if __name__ == "__main__": 65 | t = StringTest(800) 66 | -------------------------------------------------------------------------------- /scripts/tests/teststrbin.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # ***************************************************************************** 3 | # 4 | # Name: teststrbin.py 5 | # Author: Paul Robson (paul@robsons.org.uk) 6 | # Date: 28th February 2021 7 | # Purpose: Binary test classes (strings) 8 | # 9 | # ***************************************************************************** 10 | # ***************************************************************************** 11 | 12 | import random,sys 13 | from testcore import * 14 | 15 | # ***************************************************************************** 16 | # 17 | # Binary string operations (concat and compare) 18 | # 19 | # ***************************************************************************** 20 | 21 | class StrBinOpTest(Test): 22 | def getTest(self,n): 23 | s1 = self.getString() 24 | s2 = self.getString() 25 | if random.randint(0,1) == 0: 26 | return 'assert ("{0}"+"{1}") = "{2}"'.format(s1,s2,s1+s2) 27 | else: 28 | op = ["=",">","<",">=","<=","<>"][random.randint(0,5)] 29 | if op == "=": 30 | r = s1 == s2 31 | if op == ">": 32 | r = s1 > s2 33 | if op == "<": 34 | r = s1 < s2 35 | if op == "<>": 36 | r = s1 != s2 37 | if op == ">=": 38 | r = s1 >= s2 39 | if op == "<=": 40 | r = s1 <= s2 41 | return 'assert ("{0}" {1} "{2}") = {3}'.format(s1,op,s2,-1 if r != 0 else 0) 42 | 43 | def getString(self): 44 | return "".join([chr(random.randint(97,100)) for x in range(0,random.randint(0,4))]) 45 | 46 | if __name__ == "__main__": 47 | t = StrBinOpTest(500) 48 | -------------------------------------------------------------------------------- /scripts/tests/testvar.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # ***************************************************************************** 3 | # 4 | # Name: testvar.py 5 | # Author: Paul Robson (paul@robsons.org.uk) 6 | # Date: 1st March 2021 7 | # Purpose: Test assignment and variables. 8 | # 9 | # ***************************************************************************** 10 | # ***************************************************************************** 11 | 12 | import random,sys 13 | from testcore import * 14 | 15 | class AssignTest(Test): 16 | 17 | def prefixCode(self,h): 18 | self.current = {} 19 | for i in range(1,40): 20 | name = "".join([chr(random.randint(97,117)) for c in range(0,random.randint(1,5))]) 21 | if len(name) > 1: 22 | name = name[0]+"0"+name[1:] 23 | if i % 2 == 0: 24 | name = name + "$" 25 | if name not in self.current: 26 | self.current[name] = None 27 | self.names = [x for x in self.current.keys()] 28 | 29 | def getTest(self,n): 30 | var = self.names[random.randint(0,len(self.names)-1)] 31 | value = str(random.randint(0,999)) 32 | if var.endswith("$"): 33 | value = '"'+"".join([chr(random.randint(65,85)) for s in range(0,random.randint(0,7))])+'"' 34 | self.current[var] = value 35 | return "{0} = {1}".format(var,value) 36 | 37 | def postfixCode(self,h): 38 | for n in self.names: 39 | if self.current[n] is not None: 40 | h.write("assert {0} = {1}\n".format(n,self.current[n])) 41 | 42 | if __name__ == "__main__": 43 | t = AssignTest(500) 44 | -------------------------------------------------------------------------------- /scripts/vramc/__main__.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # ***************************************************************************** 3 | # 4 | # Name: __main__.py 5 | # Author: Paul Robson (paul@robsons.org.uk) 6 | # Date: 28th March 2021 7 | # Purpose: Main program for zipped vramc.zip 8 | # 9 | # ***************************************************************************** 10 | # ***************************************************************************** 11 | 12 | from vramc import * 13 | 14 | vc = VRamCompiler() 15 | vc.load("vram") 16 | vc.write() 17 | -------------------------------------------------------------------------------- /scripts/vramc/__pycache__/data.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/scripts/vramc/__pycache__/data.cpython-39.pyc -------------------------------------------------------------------------------- /scripts/vramc/__pycache__/encoder.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/scripts/vramc/__pycache__/encoder.cpython-39.pyc -------------------------------------------------------------------------------- /scripts/vramc/__pycache__/palette.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/scripts/vramc/__pycache__/palette.cpython-39.pyc -------------------------------------------------------------------------------- /scripts/vramc/__pycache__/vramc.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/scripts/vramc/__pycache__/vramc.cpython-39.pyc -------------------------------------------------------------------------------- /scripts/vramc/__pycache__/vramfile.cpython-39.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/scripts/vramc/__pycache__/vramfile.cpython-39.pyc -------------------------------------------------------------------------------- /scripts/vramc/data.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # ***************************************************************************** 3 | # 4 | # Name: data.py 5 | # Author: Paul Robson (paul@robsons.org.uk) 6 | # Date: 27th March 2021 7 | # Purpose: Rendering data with possible compression. 8 | # 9 | # ***************************************************************************** 10 | # ***************************************************************************** 11 | 12 | import re,os,sys 13 | from palette import * 14 | 15 | # ***************************************************************************** 16 | # 17 | # Data Object 18 | # 19 | # ***************************************************************************** 20 | 21 | class DataObject(VRAMBase): 22 | def __init__(self,compression = 1): 23 | self.currentCompression = compression 24 | self.data = [] 25 | # 26 | # Append data 27 | # 28 | def append(self,data): 29 | self.data += data 30 | # 31 | # Render data (compression 0) 32 | # 33 | def renderCompression0(self): 34 | r = [0x08 + self.currentCompression] 35 | p = 0 36 | while p < len(self.data): 37 | size = min(127,len(self.data)-p) 38 | r += [0x80 + size] 39 | r += self.data[p:p+size] 40 | p = p + size 41 | return r 42 | # 43 | # Render data (compression 1) 44 | # 45 | def renderCompression1(self): 46 | r = [0x08 + self.currentCompression] 47 | p = 0 48 | while p < len(self.data): 49 | p2 = self.findNextGroup(self.data,p) 50 | if p2 == p: 51 | while p2 < len(self.data) and p2-p < 63 and self.data[p] == self.data[p2]: 52 | p2 += 1 53 | r += [0xC0 + p2-p, self.data[p]] 54 | p = p2 55 | else: 56 | size = min(63,p2-p) 57 | r += [0x80 + size] 58 | r += self.data[p:p+size] 59 | p = p + size 60 | return r 61 | # 62 | # Find next group, returns end if none. 63 | # 64 | def findNextGroup(self,data,p): 65 | while p < len(data)-2 and not self.isGroup(data,p): 66 | if p >= len(data)-2: 67 | return len(data) 68 | p += 1 69 | return p 70 | # 71 | # Group at offset p 72 | # 73 | def isGroup(self,data,p): 74 | return (data[p] == data[p+1]) and (data[p+1] == data[p+2]) 75 | # 76 | # Render 77 | # 78 | def render(self): 79 | if self.currentCompression == 0: 80 | return self.renderCompression0() 81 | if self.currentCompression == 1: 82 | return self.renderCompression1() 83 | assert False 84 | 85 | if __name__ == "__main__": 86 | d = DataObject() 87 | d.append([32,45,99,116]) 88 | print(d.render()) -------------------------------------------------------------------------------- /scripts/vramc/gr_mario.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/scripts/vramc/gr_mario.png -------------------------------------------------------------------------------- /scripts/vramc/mario.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/scripts/vramc/mario.png -------------------------------------------------------------------------------- /scripts/vramc/na_mario.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/scripts/vramc/na_mario.png -------------------------------------------------------------------------------- /scripts/vramc/sq_mario.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/scripts/vramc/sq_mario.png -------------------------------------------------------------------------------- /scripts/vramc/test.vram: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/paulscottrobson/6502-basic/d4c360041bfa49427a506465e58bb0ef94beaa44/scripts/vramc/test.vram -------------------------------------------------------------------------------- /scripts/vramc/tester.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # ***************************************************************************** 3 | # 4 | # Name: tester.py 5 | # Author: Paul Robson (paul@robsons.org.uk) 6 | # Date: 27th March 2021 7 | # Purpose: Tester for vramc units 8 | # 9 | # ***************************************************************************** 10 | # ***************************************************************************** 11 | 12 | from palette import * 13 | from data import * 14 | from encoder import * 15 | from vramfile import * 16 | from PIL import Image 17 | 18 | do8Bit = False 19 | 20 | target = VRAMFile() 21 | 22 | palette = Palette() 23 | palette.setSpritePalette() 24 | 25 | target.append([1,0]) # position to 256*64 = 1024*16 26 | 27 | target.append([0x3A if do8Bit else 0x2A,0x03]) # define sprite 32x32 #1 4/8 bit colour. 28 | 29 | image = Image.open("vram/mario.png") 30 | enc = ImageEncoder() 31 | imgData = enc.encode(image,palette,not do8Bit,32,32) 32 | 33 | do = DataObject() 34 | do.append(imgData) 35 | target.append(do.render()) 36 | target.append(palette.render()) 37 | target.append([0X80]) 38 | target.write() 39 | print("File Size:",len(target.data)+2) -------------------------------------------------------------------------------- /scripts/vramc/vramfile.py: -------------------------------------------------------------------------------- 1 | # ***************************************************************************** 2 | # ***************************************************************************** 3 | # 4 | # Name: vramfile.py 5 | # Author: Paul Robson (paul@robsons.org.uk) 6 | # Date: 28th March 2021 7 | # Purpose: Build VRAM file allowing for chunking if required 8 | # 9 | # ***************************************************************************** 10 | # ***************************************************************************** 11 | 12 | # ***************************************************************************** 13 | # 14 | # VRAMFile class 15 | # 16 | # ***************************************************************************** 17 | 18 | class VRAMFile(object): 19 | def __init__(self): 20 | self.data = [ ] 21 | # 22 | def append(self,byteData): 23 | self.data += byteData 24 | # 25 | def chunk(self): 26 | pass 27 | # 28 | def write(self,fileName = None): 29 | fileName = "data.vram" if fileName is None else fileName 30 | h = open(fileName,"wb") 31 | h.write(bytes([0xFF,0xFF])) 32 | h.write(bytes(self.data)) 33 | print("VRAM File size {0} bytes.".format(len(self.data)+2)) 34 | h.close() 35 | 36 | -------------------------------------------------------------------------------- /source/assembler/asmconst.inc: -------------------------------------------------------------------------------- 1 | ; ************************************************************************************************ 2 | ; ************************************************************************************************ 3 | ; 4 | ; Name: asmconst.inc 5 | ; Purpose: Assembler constants/includes. 6 | ; Created: 15th March 2021 7 | ; Reviewed: 6th April 2021 8 | ; Author: Paul Robson = paul@robsons.org.uk 9 | ; 10 | ; ************************************************************************************************ 11 | ; ************************************************************************************************ 12 | 13 | ; ************************************************************************************************ 14 | ; 15 | ; Address Mode 16 | ; 17 | ; Constants 0-7 are determined by the structure of the 65C02 instruction set 18 | ; This ordering is also used in several lookup tables in assemblecmd.asm 19 | ; 20 | ; ************************************************************************************************ 21 | 22 | AMD_IMM = 0 ; Immediate mode. 23 | AMD_ZERO = 1 ; Zero Page 24 | AMD_ACCIMP = 2 ; Accumulator/Implied 25 | AMD_ABS = 3 ; Absolute 26 | AMD_ZEROINDY= 4 ; Zero Indirect,Y 27 | AMD_ZEROX = 5 ; Zero Page,X 28 | AMD_ABSY = 6 ; Absolute,Y 29 | AMD_ABSX = 7 ; Absolute,X 30 | AMD_ZEROIND = 8 ; Zero Indirect 31 | AMD_ZEROY = 9 ; Zero Page,Y 32 | AMD_ABSIND = 10 ; Absolute Indirect 33 | AMD_ABSINDX = 11 ; Absolute Indirect Indexed 34 | AMD_REL = 12 ; Relative 35 | AMD_ZEROINDX= 13 ; Zero Indirect,X 36 | -------------------------------------------------------------------------------- /source/assembler/assemblelabel.asm: -------------------------------------------------------------------------------- 1 | ; ************************************************************************************************ 2 | ; ************************************************************************************************ 3 | ; 4 | ; Name: assemblelabel.asm 5 | ; Purpose: Assembler label handler 6 | ; Created: 14th March 2021 7 | ; Reviewed: 6th April 2021 8 | ; Author: Paul Robson (paul@robsons.org.uk) 9 | ; 10 | ; ************************************************************************************************ 11 | ; ************************************************************************************************ 12 | 13 | .section code 14 | 15 | ; ************************************************************************************************ 16 | ; 17 | ; Assemble instruction in A, rest is (codePtr),y 18 | ; 19 | ; ************************************************************************************************ 20 | 21 | AssembleLabel: ;;