This commit is contained in:
Martin Haye 2014-05-29 07:29:10 -07:00
commit 4cd450ecc9
12 changed files with 235 additions and 515 deletions

View File

@ -25,7 +25,7 @@ Three tools are required to build and run this program: **plasm**, **acme**, and
```
./plasm -AM < hello.pla > hello.a
acme --setpc 4096 -o HELLO.REL hello.a
acme --setpc 4094 -o HELLO.REL hello.a
./plvm HELLO.REL
```
@ -45,6 +45,9 @@ make hello
for the **make** program to build all the dependencies and run the module.
## Organization of a PLASMA Source File
### Character Case
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:
@ -157,11 +160,11 @@ Excaped characters, like the `\n` above are replaces with the Carriage Return ch
| Escaped Char | ASCII Value
|:------------:|------------
| \n | NL
| \n | LF
| \t | TAB
| \r | CR
| \\\\ | \
| \\0 | 0
| \\0 | NUL
### Words
Words, 16 bit signed values, are the native sized quanta of PLASMA. All calculations, parameters, and return values are words.
@ -317,32 +320,166 @@ myobject_class:delete(an_obj)
Function definitions in PLASMA is what really seperates PLASMA from a low level language like assembly, or even a language like FORTH.
### Expressions
Exressions are comprised of operators and operations. Operator precedence follows address, arithmatic, binary, and logical from highest to lowest. Parantheses can be used to force operations to happen in a specific order.
### Control Flow
#### Address Operators
Address operators can work on any value, i.e. anything can be an address. Parentheses can be used to get the value from a variable, then use that as an address to dereference for any of the post-operators.
| OP | Pre-Operation |
|:----:|---------------------|
| ^ | byte pointer
| * | word pointer
| @ | address of
| OP | Post-Operation |
|:----:|---------------------|
| . | byte type override
| : | word type override
| [] | array index
| () | functional call
#### Arithmetic, Bitwise, and Logical Operators
| OP | Unary Operation |
|:----:|---------------------|
| - | negate
| ~ | bitwise compliment
| NOT | logical NOT
| ! | logical NOT (alternate)
| OP | Binary Operation |
|:----:|----------------------|
| * | multiply
| / | divide
| % | modulo
| + | add
| - | subtract
| << | shift left
| >> | shift right
| & | bitwise AND
| ^ | bitwise XOR
| &#124; | bitwise OR
| == | equals
| <> | not equal
| >= | greater than or equal
| > | greater than
| <= | less than or equal
| < | less than
| OR | logical OR
| 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.
#### Assignment
Assignments evaluate an expression and save the result into memory. They can be very simple or quite complex. A simple example:
```
byte a
a = 0
```
##### Empty Assignments
An assignment doesn't even have to save the expression into memory, although the expression will be avaluated. This can be useful when referencing hardware that responds just to being accessed. On the Apple II, the keyboard is read from location $C000, then the strobe, telling the hardware to prepare for another keypress is cleared by just reading the address $C010. In PLASMA, this looks like:
```
byte keypress
keypress = ^$C000 ; read keyboard
^$C010 ; read keyboard strobe, throw away value
```
#### Control Flow
PLASMA implements most of the control flow that most higher level languages provide. It may do it in a slightly different way, though. One thing you won't find in PLASMA is GOTO - there are other ways around it.
#### RETURN
##### CALL
Function calls are the easiest ways to pass control to another function. Function calls can be part of an expression, or be all by itself - the same as an empty assignment statement.
#### IF/ELSIF/ELSE/FIN
##### RETURN
`return` will exit the current definition. An optional value can be returned, however, if a value isn't specified a default of zero will be returned. All definitions return a value, regardless of whether it used or not.
#### WHEN/IS/OTHERWISE/WEND
##### IF/[ELSIF]/[ELSE]/FIN
The common `if` test can have optional `elsif` and/or `else` clauses. Any expression that is evaluated to non-zero is treated as TRUE, zero is treated as FALSE.
#### FOR/NEXT
##### WHEN/IS/[OTHERWISE]/WEND
The complex test case is handled with `when`. Basically a `if`, `elsifF`, `else` list of comparisons, it is gernerally more efficient. The `is` value can be any expression. It is evaluated and tested for equality to the `when` value.
```
when key
is 'A'
; handle A character
is 'B'
; handle B character
```
...
```
is 'Z'
; handle Z character
otherwise
; Not a known key
wend
```
With a little "Yoda-Speak", some fairly complex test can be made:
```
const FALSE = 0
const TRUE = NOT FALSE
#### WHILE/LOOP
byte a
#### REPEAT/UNTIL
when TRUE
is (a <= 10)
; 10 or less
is (a > 10) AND (a < 20)
; between 10 and 20
is (a >= 20)
; 20 or greater
wend
```
## Dynamic Heap Memory Allocation
Memory allocation isn't technically part of the PLASMA specification, but it plays such an integral part of the PLASMA environment that is is covered here.
##### FOR \<TO,DOWNTO\> [STEP]/NEXT
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
next
for a = 10 downto 1
; 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.
##### 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
while a < 10
; do something
a = b * 2 ; b is something special, I'm sure
loop
```
##### REPEAT/UNTIL
For loops that always run at least once, use the `repeat` loop.
```
repeat
update_cursor
until keypressed
```
##### BREAK
To exit early from one of the looping constructs, the `break` statement will break out of it immediately and resume control immediately following the bottom of the loop.
## Advanced Topics
There are some things about PLASMA that aren't necessary to know, but can add to it's effectiveness in a tight situation. Usually you can just code along, and the system will do a pretty reasonable job of carrying out your task. However, a little knowledge in the way to implement small assembly language routines or some coding practices just might be the ticket.
### Native Assembly Functions
Assembly code in PLASMA is implemented strictly as a pass-through to the assembler. No syntax checking, or checking at all, is made. All assembly routines *must* come after all data has been declared, and before any PLASMA function definitions.
Assembly code in PLASMA is implemented strictly as a pass-through to the assembler. No syntax checking, or checking at all, is made. All assembly routines *must* come after all data has been declared, and before any PLASMA function definitions. Native assemlbly functions can't see PLASMA labels and definitions, so they are pretty much relegated to leaf functions. Lasltly, PLASMA modules are relocatable, but labels inside assembly functions don't get flagged for fixups. The assembly code must use all relative branches and only accessing data/code at a fixed address. Data passed in on the PLASMA evalution stack is readily accessed with the X register and the zero page address of the ESTK. The X register must be properly saved, incremented, and/or decremented to remain consistent with the rest of PLASMA. Parameters are "popped" off the evaluation stack with `INX`, and the return value is "pushed" with `DEX`.
### Code Optimizations
#### Functions Without Parameters Or Local Variables
Certain simple functions that don't take parameters or use local variables will skip the Frame Stack Entry/Leave setup. That can speed up the function significantly. The following could be a very useful function:
```
def keypress
while ^$C000 < 128
loop
^$C010
return ^$C000
end
```
#### Return Values
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:
```
@ -351,7 +488,7 @@ def mydef
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`, you can save some code bytes with:
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

View File

@ -1,31 +0,0 @@
;
; Declare all imported modules and their data/functions.
;
import stdlib
predef putc, puts
end
import testcls
word print
const dec = 0
const hex = 2
end
byte spaces[] = " "
def putln
putc($0D)
end
def printnums
word i
i = 10000
repeat
print:dec(i)
puts(@spaces)
print:hex(i)
putln
i = i / 10
until i == 0
end
printnums
done

View File

@ -1,21 +0,0 @@
import STDLIB
predef memset
;
; System flags: memory allocator screen holes.
;
const restxt1 = $0001
const restxt2 = $0002
const reshgr1 = $0004
const reshgr2 = $0008
const resxhgr1 = $0010
const resxhgr2 = $0020
end
sysflags reshgr1 ; Reserve HGR page 1
memset($2000, $2000, 0) ; Clear HGR page 1
^$C054
^$C052
^$C057
^$C050
done

View File

@ -1,127 +0,0 @@
import STDLIB
predef memset, memcpy, getc, heapalloc, heapmark, heaprelease
end
import HGR1
end
const view_height = 64 ; scan count of ground view
const fix_bits = 8 ; number of fixed point bits
;
; Hardware addresses
;
const speaker=$C030
const showgraphics=$C050
const showtext=$C051
const showfull=$C052
const showmix=$C053
const showpage1=$C054
const showpage2=$C055
const showlores=$C056
const showhires=$C057
const keyboard=$C000
const keystrobe=$C010
const hgr1=$2000
const hgr2=$4000
const page1=0
const page2=1
word hgrpage[] = hgr1, hgr2
word hgrscan[] = $0000,$0400,$0800,$0C00,$1000,$1400,$1800,$1C00
word = $0080,$0480,$0880,$0C80,$1080,$1480,$1880,$1C80
word = $0100,$0500,$0900,$0D00,$1100,$1500,$1900,$1D00
word = $0180,$0580,$0980,$0D80,$1180,$1580,$1980,$1D80
word = $0200,$0600,$0A00,$0E00,$1200,$1600,$1A00,$1E00
word = $0280,$0680,$0A80,$0E80,$1280,$1680,$1A80,$1E80
word = $0300,$0700,$0B00,$0F00,$1300,$1700,$1B00,$1F00
word = $0380,$0780,$0B80,$0F80,$1380,$1780,$1B80,$1F80
word = $0028,$0428,$0828,$0C28,$1028,$1428,$1828,$1C28
word = $00A8,$04A8,$08A8,$0CA8,$10A8,$14A8,$18A8,$1CA8
word = $0128,$0528,$0928,$0D28,$1128,$1528,$1928,$1D28
word = $01A8,$05A8,$09A8,$0DA8,$11A8,$15A8,$19A8,$1DA8
word = $0228,$0628,$0A28,$0E28,$1228,$1628,$1A28,$1E28
word = $02A8,$06A8,$0AA8,$0EA8,$12A8,$16A8,$1AA8,$1EA8
word = $0328,$0728,$0B28,$0F28,$1328,$1728,$1B28,$1F28
word = $03A8,$07A8,$0BA8,$0FA8,$13A8,$17A8,$1BA8,$1FA8
word = $0050,$0450,$0850,$0C50,$1050,$1450,$1850,$1C50
word = $00D0,$04D0,$08D0,$0CD0,$10D0,$14D0,$18D0,$1CD0
word = $0150,$0550,$0950,$0D50,$1150,$1550,$1950,$1D50
word = $01D0,$05D0,$09D0,$0DD0,$11D0,$15D0,$19D0,$1DD0
word = $0250,$0650,$0A50,$0E50,$1250,$1650,$1A50,$1E50
word = $02D0,$06D0,$0AD0,$0ED0,$12D0,$16D0,$1AD0,$1ED0
word = $0350,$0750,$0B50,$0F50,$1350,$1750,$1B50,$1F50
word = $03D0,$07D0,$0BD0,$0FD0,$13D0,$17D0,$1BD0,$1FD0
word hcolor[] = $0000,$552A,$2A55,$7F7F,$8080,$D5AA,$AAD5,$FFFF
;
; def draw_scan(d8p8, scanptr)
;
asm draw_scan
!SOURCE "plvm02zp.inc"
WFIXL = $80
WFIXH = $81
WINT = $82
PIX = $83
LDA ESTKL,X
STA TMPL
LDA ESTKH,X
STA TMPH
LDA ESTKL+1,X
STA WFIXL
STA WFIXH
LDA ESTKH+1,X
LSR
STA WINT
ROR WFIXH
ROR WFIXL
LDA #$FF
SEC
SBC WFIXL
STA WFIXL
LDA #$FF
SBC WFIXH
STA WFIXH
LDA #$FF
SBC WINT
STA WINT
LDY #$01
STY PIX
DEY
- EOR ESTKH+1,X
LSR
BCC +
LDA PIX
ORA (TMP),Y
STA (TMP),Y
+ ASL PIX
BPL +
LDA #$01
STA PIX
INY
CPY #36
BEQ ++
+ LDA ESTKL+1,X
CLC
ADC WFIXL
STA WFIXL
LDA ESTKH+1,X
ADC WFIXH
STA WFIXH
LDA #$00
ADC WINT
STA WINT
BNE -
BEQ -
++ INX
RTS
end
def draw_ground(page)
byte ip
for ip = 1 to view_height
draw_scan((127 << fix_bits) / ip, hgrpage[page] + hgrscan[ip + 191 - view_height] + 2)
next
end
draw_ground(page1)
getc
^showpage1
^showtext
done

View File

@ -22,7 +22,7 @@ TXTTYPE = .TXT
#SYSTYPE = \#ff0000
#TXTTYPE = \#040000
all: $(PLASM) $(PLVM) $(PLVM02) $(CMD) TESTLIB ROD.REL
all: $(PLASM) $(PLVM) $(PLVM02) $(CMD) TESTLIB
clean:
-rm *.o *~ *.a *.SYM *.SYS *.REL TESTLIB $(PLASM) $(PLVM)
@ -44,39 +44,20 @@ $(CMD): cmd.pla cmdstub.s $(PLVM) $(PLASM)
acme --setpc 8192 -o $(CMD) cmdstub.s
TESTLIB: testlib.pla $(PLVM) $(PLASM)
./$(PLASM) -AM < testlib.pla > testlib.a
m4 < testlib.pla |./$(PLASM) -AM > testlib.a
acme --setpc 4094 -o TESTLIB testlib.a
test: test.pla TESTLIB $(PLVM) $(PLASM)
./$(PLASM) -AM < test.pla > test.a
m4 < test.pla | ./$(PLASM) -AM > test.a
acme --setpc 4094 -o TEST.REL test.a
./$(PLVM) TEST.REL
TESTCLS: testcls.pla $(PLVM) $(PLASM)
./$(PLASM) -AM < testcls.pla > testcls.a
acme --setpc 4094 -o TESTCLS testcls.a
class: class.pla TESTCLS $(PLVM) $(PLASM)
./$(PLASM) -AM < class.pla > class.a
acme --setpc 4094 -o CLASS.REL class.a
./$(PLVM) CLASS.REL
debug: test.pla TESTLIB $(PLVM) $(PLASM)
./$(PLASM) -AM < test.pla > test.a
m4 < test.pla | ./$(PLASM) -AM > test.a
acme --setpc 4094 -o TEST.REL test.a
./$(PLVM) -s TEST.REL MAIN
hello: hello.pla $(PLVM) $(PLASM)
./$(PLASM) -AM < hello.pla > hello.a
m4 < hello.pla | ./$(PLASM) -AM > hello.a
acme --setpc 4094 -o HELLO.REL hello.a
./$(PLVM) HELLO.REL
ROD.REL: rod.pla $(PLVM) $(PLASM)
./$(PLASM) -AM < rod.pla > rod.a
acme --setpc 4094 -o ROD.REL rod.a
HGR1: hgr1.pla hgr1test.pla $(PLVM) $(PLASM)
./$(PLASM) -AM < hgr1test.pla > hgr1test.a
acme --setpc 4094 -o HGR1TEST.REL hgr1test.a
./$(PLASM) -AM < hgr1.pla > hgr1.a
acme --setpc 4094 -o HGR1 hgr1.a

View File

@ -1,84 +0,0 @@
import STDLIB
predef romcall, puts
end
const speaker=$C030
const showgraphics=$C050
const showtext=$C051
const showfull=$C052
const showmix=$C053
const TRUE=$FFFF
const FALSE=$0000
const showpage1=$C054
const showpage2=$C055
const showlores=$C056
const showhires=$C057
const keyboard=$C000
const keystrobe=$C010
const hgr1=$2000
const hgr2=$4000
const page1=0
const page2=1
byte exitmsg[] = "PRESS ANY KEY TO EXIT.\n"
byte goodbye[] = "THAT'S ALL FOLKS!\n"
byte i, j, k, w, fmi, fmk, color
def textmode
romcall(0, 0, 0, 0, $FB39)
end
def home
romcall(0, 0, 0, 0, $FC58)
end
def gotoxy(x, y)
^($24) = x
romcall(y, 0, 0, 0, $FB5B)
end
def grmode
romcall(0, 0, 0, 0, $FB40)
^showlores
end
def grcolor(color)
romcall(color, 0, 0, 0, $F864)
end
def grplot(x, y)
romcall(y, 0, x, 0, $F800)
end
def colors
while TRUE
for w = 3 to 50
for i = 1 to 19
for j = 0 to 19
k = i + j
color = (j * 3) / (i + 3) + i * w / 12
fmi = 40 - i
fmk = 40 - k
romcall(color, 0, 0, 0, $F864) ;grcolor(color);
romcall(k, 0, i, 0, $F800) ;grplot(i, k);
romcall(i, 0, k, 0, $F800) ;grplot(k, i);
romcall(fmk, 0, fmi, 0, $F800) ;grplot(fmi, fmk);
romcall(fmi, 0, fmk, 0, $F800) ;grplot(fmk, fmi);
romcall(fmi, 0, k, 0, $F800) ;grplot(k, fmi);
romcall(k, 0, fmi, 0, $F800) ;grplot(fmi, k);
romcall(fmk, 0, i, 0, $F800) ;grplot(i, fmk);
romcall(i, 0, fmk, 0, $F800) ;grplot(fmk, i);
if ^keyboard >= 128
^keystrobe
return
fin
next
next
next
loop
end
grmode()
gotoxy(10,22)
puts(@exitmsg)
colors()
textmode()
home()
puts(@goodbye)
while ^keyboard < 128
loop
^keystrobe
done

View File

@ -1,150 +0,0 @@
;
; Sample PLASMA library.
;
!TO "samplib.bin", PLAIN
* = $1000
;
; DATA/CODE SEGMENT
;
_SEGBEGIN
!WORD _SEGEND-_SEGBEGIN ; LENGTH OF HEADER + CODE/DATA + BYTECODE SEGMENT
;
; MODULE HEADER
;
!WORD $DA7E ; MAGIC #
!WORD _SUBSEG ; BYTECODE SUB-SEGMENT
!WORD _INIT ; BYTECODE INIT ROUTINE
;
; MODULE DEPENDENCY LIST
; NOTE: DCI = PSUEDO OP FOR ASCII STRING WITH HI BIT SET EXCEPT LAST CHAR
;
;DCI "STDLIB"
!CT "hi.ascii"
!TX "STDLI"
!CT RAW
!TX 'B'
;DCI "FILEIO"
!CT "hi.ascii"
!TX "FILEI"
!CT RAW
!TX 'O'
!BYTE 0
;
; NATIVE CODE + GLOBAL DATA
;
COUNT !WORD 0
INCCNT
FIXUP1 INC COUNT
BNE XINIT
FIXUP2 INC COUNT+1
XINIT RTS
;
; BYTECODE SUB-SEGMENT
;
_SUBSEG
MYFUNC !BYTE $58, $01, $16 ; ENTER 1,16
!BYTE $66, $02 ; LLW 2
!BYTE $2A, $01 ; CB 1
!BYTE $54 ; CALL EXTERN(1) "OPEN"
FIXUP4 !WORD $0000
!BYTE $6E, $04 ; DLW 4
!BYTE $54 ; CALL EXTERN(3) "READ"
FIXUP5 !WORD $0000
!BYTE $30 ; DROP
!BYTE $66, $04 ; LLW 4
!BYTE $54 ; CALL EXTERN(2) ; "CLOSE"
FIXUP6 !WORD $0000
!BYTE $30 ; DROP
!BYTE $6A ; LAW COUNT
FIXUP7 !WORD $0000
!BYTE $54 ; CALL INCNT
FIXUP8 !WORD $0000
!BYTE $5A ; LEAVE
_INIT
!BYTE $5C ; RET
;
; END OF CODE/DATA + BYTECODE SEGMENT
;
_SEGEND
;
; BYTCODE FUNCTION DICTIONARY
;
!BYTE $A1 ; FIXUP FLAGS
!WORD MYFUNC ; FIXUP OFFSET
!BYTE $00 ; FIXUP LO BYTE (OF HI BYTE)/IMPORT INDEX
;
; RE-LOCATION DICTIONARY (FIXUP TABLE)
;
!BYTE $81 ; FIXUP FLAGS
!WORD FIXUP1+1 ; FIXUP OFFSET
!BYTE $00 ; FIXUP LO BYTE (OF HI BYTE)/IMPORT INDEX
!BYTE $81
!WORD FIXUP2+1
!BYTE $00
!BYTE $91 ; IMPORT FIXUP
!WORD FIXUP4
!BYTE $01 ; IMPORT INDEX 1
!BYTE $91
!WORD FIXUP5
!BYTE $03
!BYTE $91
!WORD FIXUP6
!BYTE $02
!BYTE $81
!WORD FIXUP7
!BYTE $00
!BYTE $81
!WORD FIXUP8
!BYTE $00
!BYTE 0 ; END OF RLD
;
; EXTERNAL/ENTRY SYMBOL DIRECTORY
;;
; IMPORT TABLE
;
IMPTBL ;DCI "OPEN" ; EXTERNAL SYMBOL NAME
!CT "hi.ascii"
!TX "OPE"
!CT RAW
!TX 'N'
!BYTE $10 ; EXTERNAL SYMBOL FLAG
!WORD 1 ; SYMBOL INDEX
;DCI "CLOSE"
!CT "hi.ascii"
!TX "CLOS"
!CT RAW
!TX 'E'
!BYTE $10
!WORD 2
;DCI "READ"
!CT "hi.ascii"
!TX "REA"
!CT RAW
!TX 'D'
!BYTE $10
!WORD 3
;DCI "MEMSET"
!CT "hi.ascii"
!TX "MEMSE"
!CT RAW
!TX 'T'
!BYTE $10
!WORD 4
;
; EXPORT TABLE
;
EXPTBL ;DCI "INCNT" ; ENTRY SYMBOL NAME
!CT "hi.ascii"
!TX "INCN"
!CT RAW
!TX 'T'
!BYTE $08 ; ENTRY SYMBOL FLAG
!WORD INCCNT ; OFFSET
;DCI "MYFUNC"
!CT "hi.ascii"
!TX "MYFUN"
!CT RAW
!TX 'C'
!BYTE $08
!WORD MYFUNC
!BYTE 0 ; END OF ESD

16
PLASMA/src/stdlib.plh Normal file
View File

@ -0,0 +1,16 @@
import stdlib
predef cls, gotoxy, viewport, putc, puts, getc, gets, syscall, romcall
predef heapmark, heapallocallign, heapalloc, heaprelease, heapavail
predef memset, memcpy, memxcpy
predef isugt, isuge, isult, isule
predef exec
;
; System flags: memory allocator screen holes.
;
const restxt1 = $0001
const restxt2 = $0002
const reshgr1 = $0004
const reshgr2 = $0008
const resxhgr1 = $0010
const resxhgr2 = $0020
end

View File

@ -1,45 +1,55 @@
;
; Declare all imported modules and their data/functions.
; Include all imported modules and their data/functions.
;
import stdlib
predef cls, gotoxy, viewport, puts, putc, getc
end
import testlib
predef puti, putnl
end
const mainentry = 2
;
; Predeclare any functions called before defined.
;
predef ascii, main
include(stdlib.plh)
include(testlib.plh)
;
; Declare all global variables for this module.
;
byte hello[] = "Hello, world.\n"
word defptr = @ascii, @main
word struct[] = 1, 10, 100
word struct[] = 1, 10, 100, 1000, 10000
byte spaces[] = " "
;
; Define functions.
;
def tens(start)
word i
i = start
repeat
print:hex(i)
print:str(@spaces)
print:dec(i)
print:newln()
i = i / 10
until i == 0
end
def ascii
byte i
for i = 32 to 127
i = 32
while i < 128
putc(i)
next
i = i + 1
loop
end
def nums(range)
word i
for i = -10 to range
for i = range downto -range step range/10
puti(i)
putnl
putln
next
end
export def main(range)
cls
nums(range)
nums(*range)
tens(*range*10)
viewport(12, 12, 16, 8)
ascii
viewport(0, 0, 40, 24)
@ -47,11 +57,5 @@ export def main(range)
puts(@hello)
end
export def indirect
word mainptr
mainptr = @main
return defptr:mainentry(struct:2)
end
indirect
main(@struct:6)
done

View File

@ -1,32 +0,0 @@
;
; Declare all imported modules and their data/functions.
;
import stdlib
predef putc
end
predef puti, puth
export word print[] = @puti, @puth
byte valstr[] = '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
;
; Define functions.
;
def puti(i)
if i < 0
putc('-')
i = -i
fin
if i < 10
putc(i + '0')
else
puti(i / 10)
putc(i % 10 + '0')
fin
end
def puth(h)
putc('$')
putc(valstr[(h >> 12) & $0F])
putc(valstr[(h >> 8) & $0F])
putc(valstr[(h >> 4) & $0F])
putc(valstr[ h & $0F])
end
done

View File

@ -1,13 +1,30 @@
;
; Declare all imported modules and their data/functions.
; Include all imported modules and their data/functions.
;
import stdlib
predef cls, gotoxy, puts, putc
end
include(stdlib.plh)
;
; 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.
;
def puth(h)
putc('$')
putc(valstr[(h >> 12) & $0F])
putc(valstr[(h >> 8) & $0F])
putc(valstr[(h >> 4) & $0F])
putc(valstr[ h & $0F])
end
export def puti(i)
if i < 0
putc('-')
@ -20,10 +37,11 @@ export def puti(i)
putc(i % 10 + '0')
fin
end
export def putnl
export def putln
putc($0D)
end
puts(@loadstr)
putnl
putln
done

9
PLASMA/src/testlib.plh Normal file
View File

@ -0,0 +1,9 @@
import testlib
predef puti, putln
word print
const dec = 0
const hex = 2
const newln = 4
const str = 6
const char = 8
end