diff --git a/Docs/Tutorials/PLASMA/User Manual.md b/Docs/Tutorials/PLASMA/User Manual.md index 8bbed8ac..20872340 100644 --- a/Docs/Tutorials/PLASMA/User Manual.md +++ b/Docs/Tutorials/PLASMA/User Manual.md @@ -49,10 +49,10 @@ for the **make** program to build all the dependencies and run the module. All identifiers and reserved words are case insensitive. Case is only significant inside character constants and strings. Imported and exported symbols are always promoted to upper case when resolved. Because some Apple IIs only work easily with uppercase, the eases the chance of mismatched symbol names. ### Comments -Comments are allowed throughout a PLASMA source file. The format follows that of an assembler: they begin with a `;` and comment out the rest of the line: +Comments are allowed throughout a PLASMA source file. The format follows that of C like languages: they begin with a `//` and comment out the rest of the line: ``` -; This is a comment, the rest of this line is ignored +// This is a comment, the rest of this line is ignored ``` ### Declarations @@ -188,7 +188,7 @@ byte smallarray[4] byte initbarray[] = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 byte string[64] = "Initialized string" word wlabel[] -word = 1000, 2000, 3000, 4000 ; Anonymous array +word = 1000, 2000, 3000, 4000 // Anonymous array word funclist = @myfunc, $0000 ``` Arrays can be uninitialized and reserve a size, as in `smallarray` above. Initilized arrays without a size specifier in the definition will take up as much data as is present, as in `initbarray` above. Strings are special arrays that include a hidden length byte in the beginning (Pascal strings). When specified with a size, a minimum size is reserved for the string value. Labels can be defined as arrays without size or initializers; this can be useful when overlapping labels with other arrays or defining the actual array data as anonymous arrays in following lines as in `wlabel` and following lines. Addresses of other data (must be defined previously) or function definitions (pre-defined with predef), including imported references, can be initializers. @@ -210,9 +210,9 @@ The override operator becomes more useful when multi-dimenstional arrays are use ##### Multi-Dimensional Arrays Multi-dimensional arrays are implemented as arrays of arrays, not as a single block of memory. This allows constructs such as: ``` -; -; Hi-Res scanline addresses -; +// +// Hi-Res scanline addresses +// word hgrscan[] = $2000,$2400,$2800,$2C00,$3000,$3400,$3800,$3C00 word = $2080,$2480,$2880,$2C80,$3080,$3480,$3880,$3C80 ``` @@ -245,13 +245,13 @@ Notice how xscan goes to 39 instead of 19 in the byte accessed version. #### Offsets (Structure Elements) Structures are another fundamental construct when accessing in-common data. Using fixed element offsets from a given address means you only have to pass one address around to access the entire record. Offsets are specified with a constant expression following the type override specifier. ``` -predef puti ; print an integer +predef puti // print an integer byte myrec[] word = 2 byte = "PLASMA" -puti(myrec:0) ; ID = 2 -puti(myrec.2) ; Name length = 6 (Pascal string puts length byte first) +puti(myrec:0) // ID = 2 +puti(myrec.2) // Name length = 6 (Pascal string puts length byte first) ``` This contrived example shows how one can access offsets from a variable as either `byte`s or `word`s regardless of how they were defined. This operator becomes more powerful when combined with pointers, defined next. @@ -275,9 +275,9 @@ const elem_id = 0 const elem_addr = 1 def addentry(entry, id, addr) - entry->elem_id = id ; set ID byte - entry=>elem_addr = addr ; set address - return entry + 3 ; return next enry address + entry->elem_id = id // set ID byte + entry=>elem_addr = addr // set address + return entry + 3 // return next enry address end ``` The above is equivalent to: @@ -286,16 +286,16 @@ const elem_id = 0 const elem_addr = 1 def addentry(entry, id, addr) - (entry).elem_id = id ; set ID byte - (entry):elem_addr = addr ; set address - return entry + 3 ; return next enry address + (entry).elem_id = id // set ID byte + (entry):elem_addr = addr // set address + return entry + 3 // return next enry address end ``` ##### Addresses of Data/Code Along with dereferencing a pointer, there is the question of getting the address of a variable. The `@` operator prepended to a variable name or a function definition name, will return the address of the variable/definition. From the previous example, the call to `strlen` would look like: ``` -puti(strlen(@mystring)) ; would print 17 in this example +puti(strlen(@mystring)) // would print 17 in this example ``` ##### Function Pointers @@ -311,16 +311,16 @@ def subvals(a, b) end funcptr = @addvals -puti(funcptr(5, 2)) ; Outputs 7 +puti(funcptr(5, 2)) // Outputs 7 funcptr = @subvals -puti(funcptr(5, 2)) ; Outputs 3 +puti(funcptr(5, 2)) // Outputs 3 ``` These concepts can be combined with the structure offsets to create a function table that can be easily changed on the fly. Virtual functions in object oriented languages are implemented this way. ``` predef myinit, mynew, mydelete export word myobject_class = @myinit, @mynew, @mydelete -; Rest of class data/code follows... +// Rest of class data/code follows... ``` And an external module can call into this library (class) like: ``` @@ -390,7 +390,7 @@ Address operators can work on any value, i.e. anything can be an address. Parent | AND | logical AND ### Statements -PLASMA definitions are a list of statements the carry out the algorithm. Statements are generally assignment or control flow in nature. +PLASMA definitions are a list of statements the carry out the algorithm. Statements are generally assignment or control flow in nature. Multiple statements one a single line are seperated by a ';'. Note, this use the comment seperator in previous versions of PLASMA. It is generally considered bad form to have more than one statement per line unless they are very short. #### Assignment Assignments evaluate an expression and save the result into memory. They can be very simple or quite complex. A simple example: @@ -403,8 +403,8 @@ An assignment doesn't even have to save the expression into memory, although the ``` byte keypress -keypress = ^$C000 ; read keyboard -^$C010 ; read keyboard strobe, throw away value +keypress = ^$C000 // read keyboard +^$C010 // read keyboard strobe, throw away value ``` #### Control Flow @@ -424,19 +424,19 @@ The complex test case is handled with `when`. Basically a `if`, `elsifF`, `else` ``` when key is 'A' - ; handle A character + // handle A character break is 'B' - ; handle B character + // handle B character break ``` ... ``` is 'Z' - ; handle Z character + // handle Z character break otherwise - ; Not a known key + // Not a known key wend ``` With a little "Yoda-Speak", some fairly complex test can be made: @@ -448,13 +448,13 @@ byte a when TRUE is (a <= 10) - ; 10 or less + // 10 or less break is (a > 10) AND (a < 20) - ; between 10 and 20 + // between 10 and 20 break is (a >= 20) - ; 20 or greater + // 20 or greater wend ``` A `when` clause can fall-through to the following clause, just like C `switch` statements by leaving out the `break` at the end of a clause. @@ -463,11 +463,11 @@ A `when` clause can fall-through to the following clause, just like C `switch` s Iteration over a range is handled with the `for`/`next` loop. When iterating from a smaller to larger value, the `to` construct is used; when iterating from larger to smaller, the `downto` construct is used. ``` for a = 1 to 10 - ; do something with a + // do something with a next for a = 10 downto 1 - ; do something else with a + // do something else with a next ``` An optional stepping value can be used to change the default iteration step from 1 to something else. Always use a positive value; when iterating using `downto`, the step value will be subtracted from the current value. @@ -475,10 +475,10 @@ An optional stepping value can be used to change the default iteration step from ##### WHILE/LOOP For loops that test at the top of the loop, use `while`. The loop will run zero or more times. ``` -a = c ; Who knows what c could be +a = c // Who knows what c could be while a < 10 - ; do something - a = b * 2 ; b is something special, I'm sure + // do something + a = b * 2 // b is something special, I'm sure loop ``` ##### REPEAT/UNTIL @@ -512,14 +512,14 @@ end PLASMA always returns a value from a function, even if you don't supply one. Probably the easiest optimization to make in PLASMA is to cascade a return value if you don't care about the value you return. This only works if the last thing you do before returning from your routine is calling another definition. You would go from: ``` def mydef - ; do some stuff - calldef(10) ; call some other def + // do some stuff + calldef(10) // call some other def end ``` PLASMA will effectively add a RETURN 0 to the end of your function, as well as add code to ignore the result of `calldef(10)`. As long as you don't care about the return value from `mydef` or want to use its return as the return value fromyour function (cascade the return), you can save some code bytes with: ``` def mydef - ; do some stuff - return calldef(10) ; call some other def + // do some stuff + return calldef(10) // call some other def end ``` diff --git a/Platform/Apple/tools/PLASMA/README.md b/Platform/Apple/tools/PLASMA/README.md index a010f519..6ab64d48 100644 --- a/Platform/Apple/tools/PLASMA/README.md +++ b/Platform/Apple/tools/PLASMA/README.md @@ -92,18 +92,18 @@ The PLASMA low level operations are defined as: ##PLASMA Compiler/Assembler -Although the low-level operations could easily by coded by hand, they were chosen to be an easy target for a simple compiler. Think along the lines of an advanced assembler or stripped down C compiler ( C--). Taking concepts from BASIC, Pascal, C and assembler, the PLASMA compiler is simple yet expressive. The syntax is line oriented; there is no statement delimiter except newline. +Although the low-level operations could easily by coded by hand, they were chosen to be an easy target for a simple compiler. Think along the lines of an advanced assembler or stripped down C compiler ( C--). Taking concepts from BASIC, Pascal, C and assembler, the PLASMA compiler is simple yet expressive. The syntax is line oriented. However, the ';' character can seperate multiple statements on a single line. It is generally considered bad form to have multiple statements per line unless they are very short. -Comments are allowed throughout the source, starting with the ‘;’ character. The rest of the line is ignored. +Comments are allowed throughout the source, starting with the ‘//’ symbol. The rest of the line is ignored. ``` - ; Data and text buffer constants + // Data and text buffer constants ``` Hexadecimal constants are preceded with a ‘$’ to identify them as such. ``` - $C030 ; Speaker address + $C030 // Speaker address ``` ###Constants, Variables and Functions @@ -111,27 +111,27 @@ Hexadecimal constants are preceded with a ‘$’ to identify them as such. The source code of a PLASMA module first defines imports, constants, variables and data. Constants must be initialized with a value. Variables can have sizes associated with them to declare storage space. Data can be declared with or without a variable name associated with it. Arrays, tables, strings and any predeclared data can be created and accessed in multiple ways. ``` - ; - ; Import standard library functions. - ; + // + // Import standard library functions. + // import stdlib predef putc, puts, getc, gets, cls, memcpy, memset, memclr end - ; - ; Constants used for hardware and flags - ; + // + // Constants used for hardware and flags + // const speaker = $C030 const changed = 1 const insmode = 2 - ; - ; Array declaration of screen row addresses - ; + // + // Array declaration of screen row addresses + // word txtscrn[] = $0400,$0480,$0500,$0580,$0600,$0680,$0700,$0780 word = $0428,$04A8,$0528,$05A8,$0628,$06A8,$0728,$07A8 word = $0450,$04D0,$0550,$05D0,$0650,$06D0,$0750,$07D0 - ; - ; Misc global variables - ; + // + // Misc global variables + // byte flags = 0 word numlines = 0 byte cursx, cursy @@ -143,9 +143,9 @@ Variables can have optional brackets; empty brackets don’t reserve any space f Strings are defined like Pascal strings, a length byte followed by the string characters so they can be a maximum of 255 characters long. Strings can only appear in the variable definitions of a module. String constants can’t be used in expressions or statements. ``` - ; - ; An initialized string of 64 characters - ; + // + // An initialized string of 64 characters + // byte txtfile[64] = "UNTITLED" ``` @@ -195,7 +195,7 @@ Functions with parameters or expressions to be used as a function address to cal word keyin byte key - keyin = @keyin2plus ; address-of keyin2plus function + keyin = @keyin2plus // address-of keyin2plus function key = keyin() ``` @@ -206,7 +206,7 @@ Expressions are algebraic. Data is free-form, but all operations on the evaluat ``` const speaker=$C030 - ^speaker ; click speaker + ^speaker // click speaker close(refnum) ``` @@ -257,11 +257,11 @@ Control structures affect the flow of control through the program. There are co ``` if ^pushbttn3 < 128 if key == $C0 - key = $D0 ; P + key = $D0 // P elsif key == $DD - key = $CD ; M + key = $CD // M elsif key == $DE - key = $CE ; N + key = $CE // N fin else key = key | $E0 @@ -346,7 +346,7 @@ romcall(aReg, xReg, yReg, statusReg, addr) returns a pointer to a four byte stru const xreg = 1 const getlin = $FD6A - numchars = (romcall(0, 0, 0, 0, getlin)).xreg ; return char count in X reg + numchars = (romcall(0, 0, 0, 0, getlin)).xreg // return char count in X reg ``` syscall(cmd, params) calls ProDOS, returning the status value. @@ -367,8 +367,8 @@ syscall(cmd, params) calls ProDOS, returning the status value. putc(char), puts(string), home, gotoxy(x,y), getc() and gets() are other handy utility routines for interacting with the console. ``` - putc('.') byte okstr[] = "OK" + putc('.') puts(@okstr) ``` @@ -376,7 +376,7 @@ memset(addr, len, val) will fill memory with a 16 bit value. memcpy(dstaddr, sr ``` byte nullstr[] = "" - memset(strlinbuf, maxfill * 2, @nullstr) ; fill line buff with pointer to null string + memset(strlinbuf, maxfill * 2, @nullstr) // fill line buff with pointer to null string memcpy(scrnptr, strptr + ofst + 1, numchars) ``` @@ -384,7 +384,7 @@ memset(addr, len, val) will fill memory with a 16 bit value. memcpy(dstaddr, sr ###The Original PLASMA The original design concept was to create an efficient, flexible, and expressive environment for building applications directly on the Apple II. Choosing a stack based architecture was easy after much experience with other stack based implementations. It also makes the compiler simple to implement. The first take on the stack architecture was to make it a very strict stack architecture in that everything had to be on the stack. The only opcode with operands was the CONSTANT opcode. This allowed for a very small bytecode interpreter and a very easy compile target. However, only when adding an opcode with operands that would greatly improved performance, native code generation or code size was it done. The opcode table grew slowly over time but still retains a small runtime interpreter with good native code density. -The VM was constructed such that code generation could ouput native 6502 code, threaded code into the opcode functions, or interpreted bytecodes. This gave a level of control over speed vs memory. +The VM was constructed such that code generation could output native 6502 code, threaded code into the opcode functions, or interpreted bytecodes. This gave a level of control over speed vs memory. ###The Lawless Legends PLASMA This version of PLASMA has dispensed with the native/threaded/bytecode code generation from the original version to focus on code density and the ability to interpret bytecode from AUX memory, should it be available. By focussing on the bytecode interpreter, certain optimizations were implemented that weren't posssible when allowing for threaded/native code; the interpreted bytecode is now about the same performance as the directly threaded code. diff --git a/Platform/Apple/tools/PLASMA/src/cmd.pla b/Platform/Apple/tools/PLASMA/src/cmd.pla index 0dc4a51d..2a9d1d67 100644 --- a/Platform/Apple/tools/PLASMA/src/cmd.pla +++ b/Platform/Apple/tools/PLASMA/src/cmd.pla @@ -4,37 +4,37 @@ const databuff = $2000 const MODADDR = $1000 const symtbl = $0C00 const freemem = $0006 -; -; System flags: memory allocator screen holes. -; +// +// System flags: memory allocator screen holes. +// const restxt1 = $0001 const restxt2 = $0002 const reshgr1 = $0004 const reshgr2 = $0008 const resxhgr1 = $0010 const resxhgr2 = $0020 -; -; Pedefined functions. -; +// +// Pedefined functions. +// predef syscall, call predef crout, cout, prstr, cin, rdstr predef markheap, allocheap, allocalignheap, releaseheap, availheap predef memset, memcpy predef uword_isgt, uword_isge, uword_islt, uword_isle predef loadmod, execmod, lookupstrmod -; -; System variable. -; -word version = $0010 ; 00.10 +// +// System variable. +// +word version = $0010 // 00.10 word systemflags = 0 word heap word xheap = $0800 word lastsym = symtbl byte perr word cmdptr -; -; Standard Library exported functions. -; +// +// Standard Library exported functions. +// byte stdlibstr[] = "STDLIB" byte machidstr[] = "MACHID" byte sysstr[] = "SYSCALL" @@ -81,9 +81,9 @@ word = @modadrstr, @lookupstrmod word = @machidstr, MACHID word = 0 word stdlibsym = @exports -; -; String pool. -; +// +// String pool. +// byte autorun[] = "AUTORUN" byte verstr[] = "PLASMA " byte freestr[] = "MEM FREE:$" @@ -91,14 +91,14 @@ byte errorstr[] = "ERR:$" byte okstr[] = "OK" byte huhstr[] = "?\n" byte prefix[32] = "" -; -; Utility functions -; -;asm equates included from cmdstub.s -; -; CALL PRODOS -; SYSCALL(CMD, PARAMS) -; +// +// Utility functions +// +//asm equates included from cmdstub.s +// +// CALL PRODOS +// SYSCALL(CMD, PARAMS) +// asm syscall LDA ESTKL,X LDY ESTKH,X @@ -115,10 +115,10 @@ PARAMS: !WORD 0000 STY ESTKH,X RTS end -; -; CALL 6502 ROUTINE -; CALL(ADDR, AREG, XREG, YREG, STATUS) -; +// +// CALL 6502 ROUTINE +// CALL(ADDR, AREG, XREG, YREG, STATUS) +// asm call REGVALS = SRC PHP @@ -159,9 +159,9 @@ REGVALS = SRC RTS JMPTMP JMP (TMP) end -; -; CALL LOADED SYSTEM PROGRAM -; +// +// CALL LOADED SYSTEM PROGRAM +// asm exec LDX #$00 STX IFPL @@ -173,19 +173,19 @@ asm exec BIT ROMEN JMP $2000 end -; -; EXIT -; +// +// EXIT +// asm reboot BIT ROMEN DEC $03F4 ; INVALIDATE POWER-UP BYTE JMP ($FFFC) ; RESET end -; -; SET MEMORY TO VALUE -; MEMSET(ADDR, SIZE, VALUE) -; With optimizations from Peter Ferrie -; +// +// SET MEMORY TO VALUE +// MEMSET(ADDR, SIZE, VALUE) +// With optimizations from Peter Ferrie +// asm memset LDY #$00 LDA ESTKL+2,X @@ -212,10 +212,10 @@ SETMEX INX INX RTS end -; -; COPY MEMORY -; MEMCPY(DSTADDR, SRCADDR, SIZE) -; +// +// COPY MEMORY +// MEMCPY(DSTADDR, SRCADDR, SIZE) +// asm memcpy INX INX @@ -285,11 +285,11 @@ REVCPYLP LDA (SRC),Y BNE REVCPYLP CPYMEX RTS end -; -; COPY FROM MAIN MEM TO AUX MEM. -; -; MEMXCPY(DST, SRC, SIZE) -; +// +// COPY FROM MAIN MEM TO AUX MEM. +// +// MEMXCPY(DST, SRC, SIZE) +// asm memxcpy LDA ESTKL+1,X STA $3C @@ -318,12 +318,12 @@ asm crout DEX LDA #$8D STA ESTKL,X - ; FALL THROUGH TO COUT + // FALL THROUGH TO COUT end -; -; CHAR OUT -; COUT(CHAR) -; +// +// CHAR OUT +// COUT(CHAR) +// asm cout LDA ESTKL,X BIT $BF98 @@ -335,10 +335,10 @@ asm cout BIT LCRDEN+LCBNK2 RTS end -; -; CHAR IN -; RDKEY() -; +// +// CHAR IN +// RDKEY() +// asm cin BIT ROMEN JSR $FD0C @@ -349,10 +349,10 @@ asm cin STY ESTKH,X RTS end -; -; PRINT STRING -; PRSTR(STR) -; +// +// PRINT STRING +// PRSTR(STR) +// asm prstr LDY #$00 LDA ESTKL,X @@ -375,9 +375,9 @@ asm prstr BIT LCRDEN+LCBNK2 ++ RTS end -; -; PRINT BYTE -; +// +// PRINT BYTE +// asm prbyte LDA ESTKL,X STX ESP @@ -387,9 +387,9 @@ asm prbyte BIT LCRDEN+LCBNK2 RTS end -; -; PRINT WORD -; +// +// PRINT WORD +// asm prword STX ESP TXA @@ -402,10 +402,10 @@ asm prword BIT LCRDEN+LCBNK2 RTS end -; -; READ STRING -; STR = RDSTR(PROMPTCHAR) -; +// +// READ STRING +// STR = RDSTR(PROMPTCHAR) +// asm rdstr LDA ESTKL,X STA $33 @@ -476,23 +476,23 @@ asm uword_islt INX RTS end -; -; Utility routines. -; -; A DCI string is one that has the high bit set for every character except the last. -; More efficient than C or Pascal strings. -; -;def dcitos(dci, str) -; byte len, c -; len = 0 -; repeat -; c = (dci).[len] -; len = len + 1 -; (str).[len] = c & $7F -; until !(c & $80) -; ^str = len -; return len -;end +// +// Utility routines. +// +// A DCI string is one that has the high bit set for every character except the last. +// More efficient than C or Pascal strings. +// +//def dcitos(dci, str) +// byte len, c +// len = 0 +// repeat +// c = (dci).[len] +// len = len + 1 +// (str).[len] = c & $7F +// until !(c & $80) +// ^str = len +// return len +//end asm dcitos LDA ESTKL,X STA DSTL @@ -517,22 +517,22 @@ asm dcitos STY ESTKH,X RTS end -;def stodci(str, dci) -; byte len, c -; len = ^str -; if len == 0 -; return -; fin -; c = toupper((str).[len]) & $7F -; len = len - 1 -; (dci).[len] = c -; while len -; c = toupper((str).[len]) | $80 -; len = len - 1 -; (dci).[len] = c -; loop -; return ^str -;end +//def stodci(str, dci) +// byte len, c +// len = ^str +// if len == 0 +// return +// fin +// c = toupper((str).[len]) & $7F +// len = len - 1 +// (dci).[len] = c +// while len +// c = toupper((str).[len]) | $80 +// len = len - 1 +// (dci).[len] = c +// loop +// return ^str +//end asm stodci LDA ESTKL,X STA DSTL @@ -572,22 +572,22 @@ TOUPR AND #$7F + STA ESTKL,X RTS end -; -; Module symbols are entered into the symbol table -; pre-pended with a '#' to differentiate them -; from normal symbols. -; -;def modtosym(mod, dci) -; byte len, c -; (dci).0 = '#'|$80 -; len = 0 -; repeat -; c = (mod).[len] -; len = len + 1 -; (dci).[len] = c -; until !(c & $80) -; return dci -;end +// +// Module symbols are entered into the symbol table +// pre-pended with a '#' to differentiate them +// from normal symbols. +// +//def modtosym(mod, dci) +// byte len, c +// (dci).0 = '#'|$80 +// len = 0 +// repeat +// c = (mod).[len] +// len = len + 1 +// (dci).[len] = c +// until !(c & $80) +// return dci +//end asm modtosym LDA ESTKL+1,X STA SRCL @@ -609,26 +609,26 @@ asm modtosym BCS - RTS end -; -; Lookup routines. -; -;def lookuptbl(dci, tbl) -; word match -; while ^tbl -; match = dci -; while ^tbl == ^match -; if !(^tbl & $80) -; return (tbl):1 -; fin -; tbl = tbl + 1 -; match = match + 1 -; loop -; while (^tbl & $80) -; tbl = tbl + 1 -; loop -; tbl = tbl + 3 -; loop -; return 0 +// +// Lookup routines. +// +//def lookuptbl(dci, tbl) +// word match +// while ^tbl +// match = dci +// while ^tbl == ^match +// if !(^tbl & $80) +// return (tbl):1 +// fin +// tbl = tbl + 1 +// match = match + 1 +// loop +// while (^tbl & $80) +// tbl = tbl + 1 +// loop +// tbl = tbl + 3 +// loop +// return 0 asm lookuptbl LDA ESTKL,X STA DSTL @@ -670,9 +670,9 @@ asm lookuptbl INC DSTH BCS - end -; -; ProDOS routines -; +// +// ProDOS routines +// def getpfx(path) byte params[3] @@ -719,9 +719,9 @@ def read(refnum, buff, len) perr = syscall($CA, @params) return params:6 end -; -; Heap routines. -; +// +// Heap routines. +// def availheap byte fp return @fp - heap @@ -761,11 +761,11 @@ def allocalignheap(size, pow2, freeaddr) return addr end def markheap - return heap; + return heap// end def releaseheap(newheap) - heap = newheap; - return @newheap - heap; + heap = newheap// + return @newheap - heap// end def allocxheap(size) word xaddr @@ -800,9 +800,9 @@ def allocxheap(size) fin return xaddr end -; -; Symbol table routines. -; +// +// Symbol table routines. +// def lookupsym(sym) return lookuptbl(sym, symtbl) end @@ -817,9 +817,9 @@ def addsym(sym, addr) lastsym = lastsym + 3 ^lastsym = 0 end -; -; Module routines. -; +// +// Module routines. +// def lookupmod(mod) byte dci[17] return lookuptbl(modtosym(mod, @dci), symtbl) @@ -858,13 +858,13 @@ def adddef(bank, addr, deflast) defentry = *deflast *deflast = defentry + 5 if bank - defentry=>1 = $03DC ; JSR $03DC (AUX MEM INTERP) + defentry=>1 = $03DC // JSR $03DC (AUX MEM INTERP) else - defentry=>1 = $03D6 ; JSR $03D6 (MAIN MEM INTERP) + defentry=>1 = $03D6 // JSR $03D6 (MAIN MEM INTERP) fin defentry->0 = $20 defentry=>3 = addr - defentry->5 = 0 ; NULL out next entry + defentry->5 = 0 // NULL out next entry return defentry end def lookupdef(addr, deftbl) @@ -883,9 +883,9 @@ def loadmod(mod) word moddep, rld, esd, sym byte defbank, str[16], filename[64] byte header[128] - ; - ; Read the RELocatable module header (first 128 bytes) - ; + // + // Read the RELocatable module header (first 128 bytes) + // dcitos(mod, @filename) refnum = open(@filename, iobuffer) if refnum > 0 @@ -894,18 +894,18 @@ def loadmod(mod) moddep = @header.1 defofst = modsize init = 0 - if rdlen > 4 and header:2 == $DA7E ; DAVE = magic number :-) - ; - ; This is an EXTended RELocatable (data+bytecode) module. - ; + if rdlen > 4 and header:2 == $DA7E // DAVE = magic number :-) + // + // This is an EXTended RELocatable (data+bytecode) module. + // systemflags = header:4 | systemflags defofst = header:6 defcnt = header:8 init = header:10 moddep = @header.12 - ; - ; Load module dependencies. - ; + // + // Load module dependencies. + // while ^moddep if !lookupmod(moddep) close(refnum) @@ -916,57 +916,57 @@ def loadmod(mod) fin moddep = moddep + dcitos(moddep, @str) loop - ; - ; Init def table. - ; + // + // Init def table. + // deftbl = allocheap(defcnt * 5 + 1) deflast = deftbl ^deflast = 0 if !refnum - ; - ; Reset read pointer. - ; + // + // Reset read pointer. + // refnum = open(@filename, iobuffer) rdlen = read(refnum, @header, 128) fin fin - ; - ; Alloc heap space for relocated module (data + bytecode). - ; + // + // Alloc heap space for relocated module (data + bytecode). + // moddep = moddep + 1 - modfix = moddep - @header.2 ; Adjust to skip header + modfix = moddep - @header.2 // Adjust to skip header modsize = modsize - modfix rdlen = rdlen - modfix - 2 modaddr = allocheap(modsize) memcpy(modaddr, moddep, rdlen) - ; - ; Read in remainder of module into memory for fixups. - ; - addr = modaddr; + // + // Read in remainder of module into memory for fixups. + // + addr = modaddr// repeat addr = addr + rdlen rdlen = read(refnum, addr, 4096) until rdlen <= 0 close(refnum) - ; - ; Add module to symbol table. - ; + // + // Add module to symbol table. + // addmod(mod, modaddr) - ; - ; Apply all fixups and symbol import/export. - ; + // + // Apply all fixups and symbol import/export. + // modfix = modaddr - modfix bytecode = defofst + modfix - MODADDR modend = modaddr + modsize - rld = modend ; Re-Locatable Directory - esd = rld ; Extern+Entry Symbol Directory - while ^esd ; Scan to end of ESD + rld = modend // Re-Locatable Directory + esd = rld // Extern+Entry Symbol Directory + while ^esd // Scan to end of ESD esd = esd + 4 loop esd = esd + 1 - ; - ; Locate bytecode defs in appropriate bank. - ; + // + // Locate bytecode defs in appropriate bank. + // if ^MACHID & $30 == $30 defbank = 1 defaddr = allocxheap(rld - bytecode) @@ -975,58 +975,58 @@ def loadmod(mod) defbank = 0 defaddr = bytecode fin - ; - ; Run through the Re-Location Dictionary. - ; + // + // Run through the Re-Location Dictionary. + // while ^rld if ^rld == $02 - ; - ; This is a bytcode def entry - add it to the def directory. - ; + // + // This is a bytcode def entry - add it to the def directory. + // adddef(defbank, rld=>1 - defofst + defaddr, @deflast) else addr = rld=>1 + modfix - if uword_isge(addr, modaddr) ; Skip fixups to header - if ^rld & $80 ; WORD sized fixup. + if uword_isge(addr, modaddr) // Skip fixups to header + if ^rld & $80 // WORD sized fixup. fixup = *addr - else ; BYTE sized fixup. + else // BYTE sized fixup. fixup = ^addr fin - if ^rld & $10 ; EXTERN reference. + if ^rld & $10 // EXTERN reference. fixup = fixup + lookupextern(esd, rld->3) - else ; INTERN fixup. + else // INTERN fixup. fixup = fixup + modfix - MODADDR if uword_isge(fixup, bytecode) - ; - ; Bytecode address - replace with call def directory. - ; + // + // Bytecode address - replace with call def directory. + // fixup = lookupdef(fixup - bytecode + defaddr, deftbl) fin fin - if ^rld & $80 ; WORD sized fixup. + if ^rld & $80 // WORD sized fixup. *addr = fixup - else ; BYTE sized fixup. + else // BYTE sized fixup. ^addr = fixup fin fin fin rld = rld + 4 loop - ; - ; Run through the External/Entry Symbol Directory. - ; + // + // Run through the External/Entry Symbol Directory. + // while ^esd sym = esd esd = esd + dcitos(esd, @str) if ^esd & $08 - ; - ; EXPORT symbol - add it to the global symbol table. - ; + // + // EXPORT symbol - add it to the global symbol table. + // addr = esd=>1 + modfix - MODADDR if uword_isge(addr, bytecode) - ; - ; Use the def directory address for bytecode. - ; + // + // Use the def directory address for bytecode. + // addr = lookupdef(addr - bytecode + defaddr, deftbl) fin addsym(sym, addr) @@ -1034,18 +1034,18 @@ def loadmod(mod) esd = esd + 3 loop if defbank - ; - ; Move bytecode to AUX bank. - ; + // + // Move bytecode to AUX bank. + // memxcpy(defaddr, bytecode, modsize - (bytecode - modaddr)) fin fin if perr return -perr fin - ; - ; Call init routine if it exists. - ; + // + // Call init routine if it exists. + // if init fixup = adddef(defbank, init - defofst + defaddr, @deflast)() if defbank @@ -1056,15 +1056,15 @@ def loadmod(mod) else fixup = 0 fin - ; - ; Free up the end-of-module in main memory. - ; + // + // Free up the end-of-module in main memory. + // releaseheap(modend) return fixup end -; -; Command mode -; +// +// Command mode +// def volumes byte params[4] word strbuf @@ -1120,7 +1120,7 @@ def catalog(optpath) len = type & $0F ^entry = len prstr(entry) - if type & $F0 == $D0 ; Is it a directory? + if type & $F0 == $D0 // Is it a directory? cout('/') len = len + 1 elsif entry->$10 == $FF @@ -1186,14 +1186,14 @@ def parsecmd(strptr) return cmd end def resetmemfiles - ; - ; Close all files - ; + // + // Close all files + // ^$BFD8 = 0 close(0) - ; - ; Set memory bitmap - ; + // + // Set memory bitmap + // memset($BF58, 24, 0) ^$BF58 = $CF ^$BF6F = $01 @@ -1240,13 +1240,13 @@ def execmod(modfile) heap = saveheap fin end -; -; Get heap start. -; +// +// Get heap start. +// heap = *freemem -; -; Init symbol table. -; +// +// Init symbol table. +// stodci(@stdlibstr, heap) addmod(heap, @version) while *stdlibsym @@ -1254,15 +1254,15 @@ while *stdlibsym addsym(heap, stdlibsym=>2) stdlibsym = stdlibsym + 4 loop -; -; Try to run autorun module. -; +// +// Try to run autorun module. +// resetmemfiles() execmod(@autorun) perr = 0 -; -; Print some startup info. -; +// +// Print some startup info. +// prstr(@verstr) prbyte(version.1) cout('.') diff --git a/Platform/Apple/tools/PLASMA/src/lex.c b/Platform/Apple/tools/PLASMA/src/lex.c index 7ce51ae8..c6ab6e08 100755 --- a/Platform/Apple/tools/PLASMA/src/lex.c +++ b/Platform/Apple/tools/PLASMA/src/lex.c @@ -4,7 +4,7 @@ #include "tokens.h" #include "symbols.h" -char *statement, *scanpos, *tokenstr; +char *statement, *tokenstr, *scanpos = ""; t_token scantoken, prevtoken; int tokenlen; long constval; @@ -22,28 +22,28 @@ t_token keywords[] = { ENDCASE_TOKEN, 'W', 'E', 'N', 'D', FOR_TOKEN, 'F', 'O', 'R', TO_TOKEN, 'T', 'O', - DOWNTO_TOKEN, 'D', 'O', 'W', 'N', 'T', 'O', + DOWNTO_TOKEN, 'D', 'O', 'W', 'N', 'T', 'O', STEP_TOKEN, 'S', 'T', 'E', 'P', NEXT_TOKEN, 'N', 'E', 'X', 'T', REPEAT_TOKEN, 'R', 'E', 'P', 'E', 'A', 'T', - UNTIL_TOKEN, 'U', 'N', 'T', 'I', 'L', - BREAK_TOKEN, 'B', 'R', 'E', 'A', 'K', + UNTIL_TOKEN, 'U', 'N', 'T', 'I', 'L', + BREAK_TOKEN, 'B', 'R', 'E', 'A', 'K', ASM_TOKEN, 'A', 'S', 'M', DEF_TOKEN, 'D', 'E', 'F', - EXPORT_TOKEN, 'E', 'X', 'P', 'O', 'R', 'T', - IMPORT_TOKEN, 'I', 'M', 'P', 'O', 'R', 'T', + EXPORT_TOKEN, 'E', 'X', 'P', 'O', 'R', 'T', + IMPORT_TOKEN, 'I', 'M', 'P', 'O', 'R', 'T', RETURN_TOKEN, 'R', 'E', 'T', 'U', 'R', 'N', END_TOKEN, 'E', 'N', 'D', EXIT_TOKEN, 'E', 'X', 'I', 'T', DONE_TOKEN, 'D', 'O', 'N', 'E', LOGIC_NOT_TOKEN, 'N', 'O', 'T', LOGIC_AND_TOKEN, 'A', 'N', 'D', - LOGIC_OR_TOKEN, 'O', 'R', + LOGIC_OR_TOKEN, 'O', 'R', BYTE_TOKEN, 'B', 'Y', 'T', 'E', WORD_TOKEN, 'W', 'O', 'R', 'D', CONST_TOKEN, 'C', 'O', 'N', 'S', 'T', PREDEF_TOKEN, 'P', 'R', 'E', 'D', 'E', 'F', - SYSFLAGS_TOKEN, 'S', 'Y', 'S', 'F', 'L', 'A', 'G', 'S', + SYSFLAGS_TOKEN, 'S', 'Y', 'S', 'F', 'L', 'A', 'G', 'S', EOL_TOKEN }; @@ -333,6 +333,15 @@ t_token scan(void) scanpos++; } break; + case '/': + if (scanpos[1] == '/') + scantoken = EOL_TOKEN; + else + { + scantoken = DIV_TOKEN; + scanpos++; + } + break; default: /* * Simple single character tokens. @@ -363,12 +372,21 @@ int scan_lookahead(void) char inputline[512]; int next_line(void) { - gets(inputline); - lineno++; - statement = inputline; - scanpos = inputline; - scantoken = EOL_TOKEN; - scan(); - printf("; %03d: %s\n", lineno, inputline); + if (*scanpos == ';') + { + statement = ++scanpos; + scantoken = EOL_TOKEN; + scan(); + } + else + { + gets(inputline); + lineno++; + statement = inputline; + scanpos = inputline; + scantoken = EOL_TOKEN; + scan(); + printf("; %03d: %s\n", lineno, inputline); + } return (1); } diff --git a/Platform/Apple/tools/PLASMA/src/stdlib.plh b/Platform/Apple/tools/PLASMA/src/stdlib.plh index 0df78521..804181f2 100644 --- a/Platform/Apple/tools/PLASMA/src/stdlib.plh +++ b/Platform/Apple/tools/PLASMA/src/stdlib.plh @@ -6,9 +6,9 @@ import stdlib predef isugt, isuge, isult, isule predef load, exec word MACHID, sysvars - ; - ; System flags: memory allocator screen holes. - ; + // + // System flags: memory allocator screen holes. + // const restxt1 = $0001 const restxt2 = $0002 const reshgr1 = $0004 diff --git a/Platform/Apple/tools/PLASMA/src/test.pla b/Platform/Apple/tools/PLASMA/src/test.pla index ae2b514a..e4f97f99 100755 --- a/Platform/Apple/tools/PLASMA/src/test.pla +++ b/Platform/Apple/tools/PLASMA/src/test.pla @@ -1,13 +1,13 @@ -; -; Include all imported modules and their data/functions. -; +// +// Include all imported modules and their data/functions. +// include(stdlib.plh) include(testlib.plh) -; -; Declare all global variables for this module. -; +// +// Declare all global variables for this module. +// byte hello[] = "Hello, Apple " byte a1[] = "1" @@ -20,9 +20,9 @@ word struct[] = 1, 10, 100, 1000, 10000 word ptr byte spaces[] = " " -; -; Define functions. -; +// +// Define functions. +// def tens(start) word i diff --git a/Platform/Apple/tools/PLASMA/src/testlib.pla b/Platform/Apple/tools/PLASMA/src/testlib.pla index a13c31fd..d26329ad 100755 --- a/Platform/Apple/tools/PLASMA/src/testlib.pla +++ b/Platform/Apple/tools/PLASMA/src/testlib.pla @@ -1,21 +1,21 @@ -; -; Include all imported modules and their data/functions. -; +// +// Include all imported modules and their data/functions. +// include(stdlib.plh) -; -; Module data. -; +// +// Module data. +// predef puti, puth, putln export word print[] = @puti, @puth, @putln, @puts, @putc byte valstr[] = '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' byte loadstr[] = "testlib loaded!" -; -; Define functions. -; +// +// Define functions. +// def puth(h) putc('$') @@ -26,10 +26,7 @@ def puth(h) end export def puti(i) - if i < 0 - putc('-') - i = -i - fin + if i < 0; putc('-'); i = -i; fin if i < 10 putc(i + '0') else diff --git a/Platform/Apple/virtual/src/tile/tile.s b/Platform/Apple/virtual/src/tile/tile.s index 9ad5d8ee..d9f6a43d 100644 --- a/Platform/Apple/virtual/src/tile/tile.s +++ b/Platform/Apple/virtual/src/tile/tile.s @@ -38,6 +38,10 @@ NW_MAP_LOC=$52 NE_MAP_LOC=$54 SW_MAP_LOC=$56 SE_MAP_LOC=$58 +NW_TILESET_LOC=$70 +NE_TILESET_LOC=$72 +SW_TILESET_LOC=$74 +SE_TILESET_LOC=$76 ; Map section IDs (255 = not loaded) NOT_LOADED=$FF NW_MAP_ID=$5A @@ -50,18 +54,21 @@ EAST =1 SOUTH =2 WEST =3 -;-- Variables used in drawing +;-- Variables used in drawing which can not be changed by the inner drawing loop DRAW_X_START = $5E ; Starting column being drawn (between 0 and VIEWPORT_WIDTH) DRAW_Y_START = $5F ; Starting row being drawn (between 0 and VIEWPORT_WIDTH) +DRAW_WIDTH = $62 ; Number of columns to draw for current section (cannot be destroyed by drawing loop) +DRAW_HEIGHT = $63 ; Number of rows to draw for current section (cannot be destroyed by drawing loop) +DRAW_SECTION = $64 ; Location of section data being drawn +TILE_BASE = $6B ; Location of tile data +;-- These variables are set in the outer draw section but can be destroyed by the inner routine SECTION_X_START = $60 ; X Offset relative to current section being drawn SECTION_Y_START = $61 ; Y Offset relative to current section being drawn -DRAW_WIDTH = $62 ; Number of columns to draw for current section (cannot be destroyed by drawing loop) -DRAW_HEIGTH = $63 ; Number of rows to draw for current section (cannot be destroyed by drawing loop) -DRAW_SECTION = $64 ; Location of section data being drawn X_COUNTER = $66 ; Loop counter used during drawing Y_COUNTER = $67 ; Loop counter used during drawing -ROW_LOCATION = $68 ; Used for pointing at row offset in map data - +Y_LOC = $68 ; Current row being drawn (between 0 and VIEWPORT_WIDTH) +ROW_LOCATION = $69 ; Used for pointing at row offset in map data +TILE_SOURCE = $6D ; Location of tile data ; >> INIT (reset map drawing vars) INIT LDA #NOT_LOADED @@ -76,12 +83,12 @@ INIT ;---------------------------------------------------------------------- ; >> START LOADING MAP SECTIONS -START_LOAD +START_MAP_LOAD LDX #0 LDA #START_LOAD JMP mainLoader !macro startLoad { - JSR START_LOAD + JSR START_MAP_LOAD } ;---------------------------------------------------------------------- @@ -113,17 +120,17 @@ LOAD_SECTION ;---------------------------------------------------------------------- ; >> FINISH LOADING MAP SECTIONS -FINISH_LOAD +FINISH_MAP_LOAD LDX #0 ; 1 to keep open for next load, 0 for close so you can flip to HGR page 2 LDA #FINISH_LOAD JMP mainLoader !macro finishLoad { - JSR FINISH_LOAD + JSR FINISH_MAP_LOAD } ;---------------------------------------------------------------------- -; >> RELEASE MAP SECTION -!macro releaseMapSection ptr { +; >> RELEASE MAP SECTION OR TILESET +!macro freeResource ptr { ; --> free up unused resource LDX ptr LDY ptr+1 @@ -133,6 +140,18 @@ FINISH_LOAD ;---------------------------------------------------------------------- ; >> LOAD TILES ; Load tile resource (A = Resource ID) +LOAD_TILESET + TAY + LDX #RES_TYPE_TILESET + LDA #QUEUE_LOAD + JMP mainLoader +!macro loadTileset mapData, ptr { + LDY #4 + LDA (mapData),Y + JSR LOAD_TILESET + STX ptr + STY ptr+1 +} ;---------------------------------------------------------------------- ; >> MOVE NORTH ; Check for boundary @@ -170,8 +189,8 @@ SET_XY ; >> TRIGGER SCRIPT AT TILE (X,Y = Coordinates in section) ;---------------------------------------------------------------------- !macro move_word from, to { - !move_byte from, to - !move_byte from+1, to+1 + +move_byte from, to + +move_byte from+1, to+1 } !macro move_byte from, to { @@ -179,110 +198,139 @@ SET_XY STX to } +FREE_ALL_TILES + +freeResource NW_TILESET_LOC + +freeResource NE_TILESET_LOC + +freeResource SW_TILESET_LOC + +freeResource SE_TILESET_LOC + RTS +!macro freeAllTiles { + JSR FREE_ALL_TILES +} + +LOAD_ALL_TILES + +loadTileset NW_MAP_LOC, NW_TILESET_LOC + +loadTileset NE_MAP_LOC, NW_TILESET_LOC + +loadTileset SW_MAP_LOC, NW_TILESET_LOC + +loadTileset SE_MAP_LOC, NW_TILESET_LOC + RTS +!macro loadAllTiles { + JSR LOAD_ALL_TILES +} + ; >> CROSS NORTH BOUNDARY (Load next section to the north) !zone CROSS_NORTH - !releaseMapSection SW_MAP_LOC - !releaseMapSection SE_MAP_LOC + +freeAllTiles + +freeResource SW_MAP_LOC + +freeResource SE_MAP_LOC LDA REL_Y CLC ADC #SECTION_HEIGHT STA REL_Y - !move_byte NW_MAP_ID, SW_MAP_ID - !move_word NW_MAP_LOC, SW_MAP_LOC - !move_byte NE_MAP_ID, SE_MAP_ID - !move_word NE_MAP_LOC, SE_MAP_LOC + +move_byte NW_MAP_ID, SW_MAP_ID + +move_word NW_MAP_LOC, SW_MAP_LOC + +move_byte NE_MAP_ID, SE_MAP_ID + +move_word NE_MAP_LOC, SE_MAP_LOC ; Get new NW section - !startLoad - LDA (SW_MAP_LOC) + +startLoad + LDY #00 + LDA (SW_MAP_LOC),Y STA NW_MAP_ID - !loadSection NW_MAP_LOC + +loadSection NW_MAP_LOC ; Get the new NE section - LDA (SE_MAP_LOC) + LDA (SE_MAP_LOC),Y STA NE_MAP_ID - !loadSection NE_MAP_LOC - !finishLoad + +loadSection NE_MAP_LOC + +loadAllTiles + +finishLoad RTS ;---------------------------------------------------------------------- ; >> CROSS EAST BOUNDARY (Load next section to the east) !zone CROSS_EAST - !releaseMapSection NW_MAP_LOC - !releaseMapSection SW_MAP_LOC + +freeAllTiles + +freeResource NW_MAP_LOC + +freeResource SW_MAP_LOC LDA REL_X SEC SBC #SECTION_WIDTH STA REL_X - !move_byte NE_MAP_ID, NW_MAP_ID - !move_word NE_MAP_LOC, NW_MAP_LOC - !move_byte SE_MAP_ID, SW_MAP_ID - !move_word SE_MAP_LOC, SW_MAP_LOC + +move_byte NE_MAP_ID, NW_MAP_ID + +move_word NE_MAP_LOC, NW_MAP_LOC + +move_byte SE_MAP_ID, SW_MAP_ID + +move_word SE_MAP_LOC, SW_MAP_LOC ; Get new NE section - !startLoad + +startLoad LDY #EAST LDA (NW_MAP_LOC),Y STA NE_MAP_ID - !loadSection NE_MAP_LOC + +loadSection NE_MAP_LOC ; Get the new SE section LDY #EAST LDA (SW_MAP_LOC),Y STA SE_MAP_ID - !loadSection SE_MAP_LOC - !finishLoad + +loadSection SE_MAP_LOC + +loadAllTiles + +finishLoad RTS ;---------------------------------------------------------------------- ; >> CROSS SOUTH BOUNDARY (Load next section to the south) !zone CROSS_SOUTH - !releaseMapSection NW_MAP_LOC - !releaseMapSection NE_MAP_LOC + +freeAllTiles + +freeResource NW_MAP_LOC + +freeResource NE_MAP_LOC LDA REL_Y SEC SBC #SECTION_HEIGHT STA REL_Y - !move_byte SW_MAP_ID, NW_MAP_ID - !move_word SW_MAP_LOC, NW_MAP_LOC - !move_byte SE_MAP_ID, NE_MAP_ID - !move_word SE_MAP_LOC, NE_MAP_LOC + +move_byte SW_MAP_ID, NW_MAP_ID + +move_word SW_MAP_LOC, NW_MAP_LOC + +move_byte SE_MAP_ID, NE_MAP_ID + +move_word SE_MAP_LOC, NE_MAP_LOC ; Get new SW section - !startLoad + +startLoad LDY #SOUTH LDA (NW_MAP_LOC),Y STA SW_MAP_ID - !loadSection SW_MAP_LOC + +loadSection SW_MAP_LOC ; Get the new SE section LDY #SOUTH LDA (NE_MAP_LOC),Y STA SE_MAP_ID - !loadSection SE_MAP_LOC - !finishLoad + +loadSection SE_MAP_LOC + +loadAllTiles + +finishLoad RTS ;---------------------------------------------------------------------- ; >> CROSS WEST BOUNDARY (load next section to the west) !zone CROSS_WEST - !releaseMapSection NE_MAP_LOC - !releaseMapSection SE_MAP_LOC + +freeAllTiles + +freeResource NE_MAP_LOC + +freeResource SE_MAP_LOC LDA REL_X CLC ADC #SECTION_WIDTH STA REL_X - !move_byte NW_MAP_ID, NE_MAP_ID - !move_word NW_MAP_LOC, NE_MAP_LOC - !move_byte SW_MAP_ID, SE_MAP_ID - !move_word SW_MAP_LOC, SE_MAP_LOC + +move_byte NW_MAP_ID, NE_MAP_ID + +move_word NW_MAP_LOC, NE_MAP_LOC + +move_byte SW_MAP_ID, SE_MAP_ID + +move_word SW_MAP_LOC, SE_MAP_LOC ; Get new NW section - !startLoad + +startLoad LDY #WEST LDA (NE_MAP_LOC),Y STA NW_MAP_ID - !loadSection NW_MAP_LOC + +loadSection NW_MAP_LOC ; Get the new SE section LDY #WEST LDA (SE_MAP_LOC),Y STA SW_MAP_ID - !loadSection SW_MAP_LOC - !finishLoad + +loadSection SW_MAP_LOC + +loadAllTiles + +finishLoad RTS ;---------------------------------------------------------------------- ; >> SET PLAYER TILE (A = tile) @@ -291,7 +339,7 @@ CROSS_WEST ;---------------------------------------------------------------------- ; >> DRAW !zone draw -!macro drawMapSection ptr, deltaX, deltaY { +!macro drawMapSection mapPtr, tilesetPtr, deltaX, deltaY { ; Determine X1 and X2 bounds for what is being drawn LDA REL_X SEC @@ -304,7 +352,7 @@ CROSS_WEST CLC ADC #VIEWPORT_WIDTH CMP #SECTION_WIDTH - BLT .11 + BMI .11 LDA #SECTION_WIDTH .11 SEC @@ -322,14 +370,15 @@ CROSS_WEST CLC ADC #VIEWPORT_HEIGHT CMP #SECTION_HEIGHT - BLT .21 + BMI .21 LDA #SECTION_HEIGHT .21 SEC SBC SECTION_Y_START STA DRAW_HEIGHT - !move_word ptr, DRAW_SECTION - jsr mainDraw + +move_word mapPtr, DRAW_SECTION + +move_word tilesetPtr, TILE_BASE + JSR MainDraw } DRAW @@ -340,20 +389,22 @@ DRAW .checkNorthQuads LDA REL_Y CMP SECTION_HEIGHT+VIEWPORT_VERT_PAD - BGE .checkSouthQuads + BMI .checkNWQuad + JMP .checkSouthQuads +.checkNWQuad ; Check for NW quadrant area LDA REL_X CMP SECTION_WIDTH+VIEWPORT_HORIZ_PAD - BGE .checkNEQuad - !drawMapSection NW_MAP_LOC, 0, 0 + BPL .checkNEQuad + +drawMapSection NW_MAP_LOC, NW_TILESET_LOC, 0, 0 ; Check for NE quadrant area .checkNEQuad LDA REL_X CMP #VIEWPORT_HORIZ_PAD+1 - BLT .finishTopQuads + BMI .finishTopQuads LDA DRAW_WIDTH STA DRAW_X_START - !drawMapSection NE_MAP_LOC, SECTION_WIDTH, 0 + +drawMapSection NE_MAP_LOC, NE_TILESET_LOC, SECTION_WIDTH, 0 .finishTopQuads ;Update Y start for bottom quadrants LDA DRAW_HEIGHT @@ -365,21 +416,21 @@ DRAW ; Check for SW quadrant area LDA REL_X CMP SECTION_WIDTH+VIEWPORT_HORIZ_PAD - BGE .checkSEQuad - !drawMapSection SW_MAP_LOC, 0, SECTION_HEIGHT + BPL .checkSEQuad + +drawMapSection SW_MAP_LOC, SW_TILESET_LOC, 0, SECTION_HEIGHT .checkSEQuad ; Check for SE quadrand area LDA REL_X CMP #VIEWPORT_HORIZ_PAD+1 - BGE .drawSEQuad + BPL .drawSEQuad RTS .drawSEQuad LDA DRAW_WIDTH STA DRAW_X_START - !drawMapSection SE_MAP_LOC, SECTION_WIDTH, SECTION_HEIGHT + +drawMapSection SE_MAP_LOC, SE_TILESET_LOC, SECTION_WIDTH, SECTION_HEIGHT RTS -.mainDraw +MainDraw ;----- Tracking visible tile data ----- ;There are a total of 512 screen holes in a hires page located in xx78-xx7F and xxF8-xxFF ;We only need 81 screen holes to track the 9x9 visible area. So to do this a little translation is needed @@ -399,9 +450,14 @@ DRAW COL_OFFSET = 2 ROW_OFFSET = 3 + LDA DRAW_HEIGHT + STA Y_COUNTER + LDA DRAW_Y_START + STA Y_LOC +.rowLoop ; Identify start of map data (upper left) ; Self-modifying code: Update all the STA statements in the drawTile section - LDY DRAW_Y_START + LDY Y_LOC LDA tblHGRl+ROW_OFFSET, Y ADC #COL_OFFSET TAX @@ -431,7 +487,7 @@ ROW_OFFSET = 3 CLC LDA SECTION_Y_START ;row * 2 ASL - ADC #HEADER_LENGTH + ADC #HEADER_LENGTH ; +6 ADC SECTION_X_START STA ROW_LOCATION LDA SECTION_Y_START ; row * 4 @@ -449,24 +505,15 @@ ROW_OFFSET = 3 LDA DRAW_SECTION + 1 ADC #$00 ; This is a short way for handling carry without a branch STA ROW_LOCATION + 1 - LDA DRAW_SECTION + LDA DRAW_SECTION ; DRAW_SECTION is done at the very end in case it causes an overflow ADC ROW_LOCATION STA ROW_LOCATION ; Handle carry if needed BCC .doneCalculatingLocation INC ROW_LOCATION + 1 .doneCalculatingLocation - CLC - LDA SECTION_Y_START - ASL - ADC ROW_LOCATION - STA ROW_LOCATION - LDA SECTION_Y_START - ASL - ASL - ADC ROW_LOCATION - STA ROW_LOCATION - + LDA DRAW_WIDTH + STA X_COUNTER LDX DRAW_X_START ; Display row of tiles .next_col @@ -479,15 +526,15 @@ ROW_OFFSET = 3 ASL ASL STA TILE_SOURCE - LDA TILE_BASE + LDA TILE_BASE + 1 ADC #$00 STA TILE_SOURCE+1 LDA TILE_BASE ADC TILE_SOURCE STA TILE_SOURCE - BCC .doenCalculatingTileLocation + BCC .doneCalculatingTileLocation INC TILE_SOURCE+1 -.doenCalculatingTileLocation +.doneCalculatingTileLocation ; Is there a NPC there? ; No, use map tile ; Yes, use NPC tile @@ -502,27 +549,33 @@ ROW_OFFSET = 3 ASL TAX .drawTile !for row, 16 { -.0 LDA (TILE_SOURCE),Y -.2 STA DRAW_ROW, X -.5 INY -.6 INX -.7 LDA (TILE_SOURCE),Y -.9 STA DRAW_ROW, X - !if row < 15 { -.12 INY -.13 DEX - } + LDA (TILE_SOURCE),Y ;0 + STA $2000, X ;2 + INY ;5 + INX ;6 + LDA (TILE_SOURCE),Y ;7 + STA $2000, X ;9 + !if row < 15 { + INY ;12 + DEX ;13 } } DEC X_COUNTER BMI .next_row + INX TXA ; Outside the drawing part we need to put X back (divide by 2) LSR TAX - BNE .next_col + JMP .next_col ; Increment row .next_row - + DEC Y_COUNTER + BPL .notDone + RTS +.notDone + INC Y_LOC + INC SECTION_Y_START + JMP .rowLoop ; Draw player tblHGRl