1
0
mirror of https://github.com/dschmenk/PLASMA.git synced 2024-07-08 09:28:57 +00:00

Merge pull request #4 from dschmenk/master

Merge latest upstream changes
This commit is contained in:
ZornsLemma 2017-08-14 20:50:55 +01:00 committed by GitHub
commit e3198fc3d9
18 changed files with 1002 additions and 370 deletions

View File

@ -67,6 +67,7 @@ Different projects have led to the architecture of PLASMA, most notably Apple Pa
- [Assignment](#assignment)
- [Empty Assignments](#empty-assignments)
- [Increment and Decrement](#increment-and-decrement)
- [Lambda (Anonymous) Functions](#lambda-functions)
- [Control Flow](#control-flow)
- [CALL](#call)
- [RETURN](#return)
@ -464,6 +465,22 @@ keyin = @keyin2plus // address-of keyin2plus function
key = keyin()
```
Lambda functions are anonymous functions that can be used to return a value (or multiple values). They can be used as function pointers to routines that need a quick and dirty expression. They are written an '&' (a poor man's lambda symbol) followed by parameters in parentheses, and the resultant expression. There are no local variables allowed.
```
word result
def eval_op(x, y, op)
result = result + op(x, y)
return result
end
def keyin(x, y, key)
if key == '+'
eval_op(x, y, &(x, y) x + y)
fin
end
````
Control statements affect the flow of control through the program. There are conditional and looping constructs. The most widely used is probably the `if`/`elsif`/`else`/`fin` construct.
```
@ -1004,7 +1021,6 @@ keypress = ^$C000 // read keyboard
^$C010 // read keyboard strobe, throw away value
```
### Increment and Decrement
PLASMA has an increment and decrement statement. This is different than the increment and decrement operations in languages like C and Java. Instead, they cannot be part of an expression and only exist as a statement in postfix:
@ -1019,6 +1035,36 @@ i-- // decrement i by 1
puti(i) // print 4
```
### Lambda Functions
A Lambda function is a simple, anonymous function that can be passed to a function or assigned to a variable. It is called as a function pointer. The function can take a number of parameters and return a value based on the parameters and/or global values. By enclosing the expression of the lambda function in parenthesis, multiple values can be returned.
```
def what_op(a, b, op)
puti(a)
puts(" ? ")
puti(b)
puts(" = ")
puti(op(a, b))
putln
end
def lambdas
word lambda1
word lambda2
word x, y
lambda1 = &(a, b) a + b
lambda2 = &(a, b) (a + b, a - b)
x = lambda1(1, 2) // This will return 3
x, y = lambda2(3, 4)#2 // This will return 7, -1 (the #2 denotes two returned values instead of the default of one)
what_op(10, 20, &(a, b) a * b) // This will print 10 ? 20 = 200
return &(x, y, z) x * z / y // You can even return lambdas from definitions (these x, y are different from the locally defined x, y)
end
````
There are some limitations to lambda functions. They don't have any local variables except for the parameters. They can only return an expression; there are no control flow statements allowed. Lastly, they can only be defined inside another definition. They cannot be defined in global data space or in the module main function (it gets deallocated after initialization).
### Control Flow
PLASMA implements most of the control flow that most high-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.
@ -1275,6 +1321,7 @@ The compact code representation comes through the use of opcodes closely matched
| $58 | ENTER | allocate frame size and copy stack parameters to local frame
| $5A | LEAVE | deallocate frame and return from sub routine call
| $5C | RET | return from sub routine call
| $5E | CFFB | constant with $FF MSB
| $60 | LB | load byte from top of stack address
| $62 | LW | load word from top of stack address
| $64 | LLB | load byte from frame offset
@ -1309,6 +1356,8 @@ Probably the most exciting development is the support for the Apple ///. PLASMA
# Links
[PLASMA on Acorn Beeb](http://stardot.org.uk/forums/viewtopic.php?f=55&t=12306&p=163288#p163288)
[ACME 6502 assembler](https://sourceforge.net/projects/acme-crossass/)
[HiDef PLASMA KFEST 2015 video](https://archive.org/details/Kansasfest2015ThePlasmaLanguage)

93
doc/Rogue Instructions.md Executable file
View File

@ -0,0 +1,93 @@
# PLASMA goes ROGUE
## Introduction
This version of ROGUE is somewhat different than others. It is very simple in most ways, but I have developed a (I think) unique visibility algorithm that runs extremely fast. Fast enough to run interpreted by the PLASMA VM on a 1 MHz 6502, and space efficient enough to allow for large (in the future) dungeons. The unique feature of this ROGUE is that lighting becomes critical and strategic. You are in dark catacombs, after all. You enter with a lit lamp, throwing off a circle of light. There are also torches throughout the catacombs that light up a small surrounding circle of light. Other items in the catacombs are mana (health+energy increase), a key, a raft, and gold. You will also encounter a number of enemies that will track you down to try and kill you. You will also encounter doors, locked doors, windows, water, and crevasses.
## Strategy
As you travel through the catacombs, you must watch your health, energy, and lamp oil levels. Once health reaches zero, you are dead. As energy reaches zero, your vision will narrow and you will no longer be able to run. When the lamp oil runs out, you will be cast into darkness. If you see any torches in your field of vision, you can navigate to them. Taking the torch will extinguish the torch and replenish some of your lamp oil. Note that as you travel through the catacombs, your map of what you have seen will automatically fill in. But, if you are in the dark, you cannot read your map. You must turn on your lamp or get next to a torch before you can read the map again. If you are in the dark and cant see any torches in your field of vision, you are in complete darkness. It is easy to lose your bearings. As such, the absolute direction movements no longer work (NSEW) - you will end up in a random direction if you try. However, the relative turns, left/right and forward/backward controls continue to work (that you can do in the dark).
Being in the dark can be advantageous, however. All the enemies in the catacombs can see you if you are in light, just as you can see them. If you are in darkness, they can't see you, and you can move around without being tracked. Don't run into them! Also, don't fall off a crevasse. You will hear certain noises giving you feedback on what is going on. A simple beep when you run into walls. A groan when an enemy moves towards you. A bleep when you pick an item up. Other noises when you fall over an edge or win a battle. These can be used strategically when moving in the dark.
Health will slowly improve as you move around. However, energy is depleted as you move. Mana will increase both health and energy. If health is already at 100, it wont go any higher. Same for energy, but it is important to keep both high. When energy goes low, you can no longer move quickly and your field-of-vision narrows. When health goes to zero, you are dead.
## Tile Description
As ROGUE uses the text screen for display, a little creativity is required to interpret the map. These are the characters you will see and what the represent. Once you get the hang of it, it will be just like looking at the unencoded Matrix.
```
Screen Character      Represents
   #                    Wall
   .                    Floor
   :                    Window (barred opening)
   +                    Door
   %                   Locked Door (need key to open)
   ' ' space            Crevasse (pit - don't fall in)
   =                  Exit
   -                  Entrance
   *                    Torch
   &                    Mana
   ,                    Key (yep, hard to spot)
   @                    Raft (need to cross water)
<<< Water
   >>>              Water (you will drown without raft)
   $                    Gold
Flashing               Entity
   T                    Thief
   O                    Ogre
   Z                    Zombie
   R                    Rogue
 Player               Facing Direction
   ^                    North
   \                    NE
   >                    East
   /                    SE
   v                    South
   \                    SW
   <                    West
   /                    NW
```
Tiles in light are inverse. Entities are displayed only when lit and in field of view. The map is only visible when lit, i.e lamp is on or standing next to a torch.
## Interaction
```
Keyboard commands      Action
   Q                   Run (Quick)
   W up-arrow           Forward
   S down-arrow         Backward
   A left-arrow         Turn left
   D right-arrow       Turn right
   I                   Move N
   J                   Move W
   K                   Move E
   M                   Move S
   < ,                 Turn lamp down
   > .                 Turn lamp up/on
   O                   Turn lamp off
   Space-bar            Open door
   Return               Pick up item
   X                   Exit (die)
```
Whenever you and an enemy end up on the same tile, battle commences. As you win fights, your skill increases, improving your attack effectiveness. As you advance through the catacombs, the enemies become more powerful. You will need to replenish health and energy with mana. Don't forget, the alternative to fighting is stealth in the darkness. During battle, you have the option to run. If you have low energy, you won't get very far. Also, when fighting, you get turned around so you can't depend on the direction you were facing before fighting. Running ('Q'uick) will get you away from enemies but will use much more energy.
If you should die, restart the game by typing:
```
+rogue
```
## Map Levels
Level maps are up to 62x62 in size (plus a wall boundary for an effective 64x64 map size). They can be smaller than this. The game will end when it tries to load an non-existent level. Levels start at file name “LEVEL0“ and can go all the way to “LEVEL9“, but must be sequential.
There are two levels included on the disk, and an empty level for you to use as a template. You can edit the map levels, and add your own. They are simple ASCII text files. The included sandbox editor can edit the maps right on the disk. type:
```
-sandbox level.empty
```
after exiting from ROGUE. Make your changes and save it as LEVEL0" to "LEVEL9". The next free level is currently "LEVEL2". You may also edit an existing level:
```
-sandbox level0
```
for instance.

View File

@ -1,178 +0,0 @@
{\rtf1\ansi\ansicpg1252\cocoartf1343\cocoasubrtf160
{\fonttbl\f0\froman\fcharset0 TimesNewRomanPSMT;\f1\fmodern\fcharset0 Courier;\f2\fswiss\fcharset0 Helvetica;
}
{\colortbl;\red255\green255\blue255;}
{\info
{\author David Schmenk}}\margl1440\margr1440\vieww12540\viewh16140\viewkind1
\deftab720
\pard\pardeftab720\qc
\f0\b\fs36 \cf0 \expnd0\expndtw0\kerning0
PLASMA goes ROGUE\
\pard\pardeftab720
\fs28 \cf0 \expnd0\expndtw0\kerning0
\ul \ulc0 Introduction\
\pard\pardeftab720
\b0\fs24 \cf0 \expnd0\expndtw0\kerning0
\ulnone This version of ROGUE is somewhat different than others. It is very simple in most ways, but I have developed a (I think) unique visibility algorithm that runs extremely fast. Fast enough to run interpreted by the PLASMA VM on a 1 MHz 6502, and space efficient enough to allow for large (in the future) dungeons. The unique feature of this ROGUE is that lighting becomes critical and strategic. You are in dark catacombs, after all. You enter with a lit lamp, throwing off a circle of light. There are also torches throughout the catacombs that light up a small surrounding circle of light. Other items in the catacombs are mana (health+energy increase), a key, a raft, and gold. You will also encounter a number of enemies that will track you down to try and kill you. You will also encounter doors, locked doors, windows, water, and crevasses.\
\
\pard\pardeftab720
\b\fs28 \cf0 \expnd0\expndtw0\kerning0
\ul \ulc0 Strategy\
\pard\pardeftab720
\b0\fs24 \cf0 \expnd0\expndtw0\kerning0
\ulnone As you travel through the catacombs, you must watch your health, energy, and lamp oil levels. Once health reaches zero, you are dead. As energy reaches zero, your vision will narrow and you will no longer be able to run. When the lamp oil runs out, you will be cast into darkness. If you see any torches in your field of vision, you can navigate to them. Taking the torch will extinguish the torch and replenish some of your lamp oil. Note that as you travel through the catacombs, your map of what you have seen will automatically fill in. But, if you are in the dark, you cannot read your map. You must turn on your lamp or get next to a torch before you can read the map again. If you are in the dark and can\'92t see any torches in your field of vision, you are in complete darkness. It is easy to lose your bearings. As such, the absolute direction movements no longer work (NSEW) - you will end up in a random direction if you try. However, the relative turns, left/right and forward/backward controls continue to work (
\b \expnd0\expndtw0\kerning0
that
\b0 \expnd0\expndtw0\kerning0
you can do in the dark).\
\
Being in the dark can be advantageous, however. All the enemies in the catacombs can see you if you are in light, just as you can see them. If you are in darkness, they can't see you, and you can move around without being tracked. Don't run into them! Also, don't fall off a crevasse. You will hear certain noises giving you feedback on what is going on. A simple beep when you run into walls. A groan when an enemy moves towards you. A bleep when you pick an item up. Other noises when you fall over an edge or win a battle. These can be used strategically when moving in the dark.\
\
Health will slowly improve as you move around. However, energy is depleted as you move. Mana will increase both health and energy. If health is already at 100, it won\'92t go any higher. Same for energy, but it is important to keep both high. When energy goes low, you can no longer move quickly and your field-of-vision narrows. When health goes to zero, you are dead.\
\
\pard\pardeftab720
\b\fs28 \cf0 \expnd0\expndtw0\kerning0
\ul \ulc0 Tile Description\
\pard\pardeftab720
\b0\fs24 \cf0 \expnd0\expndtw0\kerning0
\ulnone As ROGUE uses the text screen for display, a little creativity is required to interpret the map. These are the characters you will see and what the represent. Once you get the hang of it, it will be just like looking at the unencoded Matrix.\
\
\pard\pardeftab720
\f1 \cf0 \expnd0\expndtw0\kerning0
\ul \ulc0 Screen Character\expnd0\expndtw0\kerning0
\ulnone \'a0 \'a0 \'a0\expnd0\expndtw0\kerning0
\ul Represents\
\pard\pardeftab720
\cf0 \expnd0\expndtw0\kerning0
\ulnone \'a0\'a0\'a0# \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0Wall\
\'a0\'a0\'a0. \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0Floor\
\'a0\'a0\'a0: \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0Window (barred opening)\
\'a0 \'a0+ \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0Door\
\'a0 \'a0% \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 Locked Door (need key to open)\
\'a0\'a0\'a0' ' space \'a0 \'a0 \'a0 \'a0 \'a0 \'a0Crevasse (pit - don't fall in)\
\'a0\'a0\'a0= \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0Exit\
\'a0\'a0\'a0- \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0Entrance\
\'a0\'a0\'a0* \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0Torch\
\'a0\'a0\'a0& \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0Mana\
\'a0\'a0\'a0, \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0Key (yep, hard to spot)\
\'a0 \'a0@ \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0Raft (need to cross water)\
<<< Water\
\'a0 \'a0>>> \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0Water (you will drown without raft)\
\'a0\'a0\'a0$ \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0Gold\
\
\pard\pardeftab720
\cf0 \expnd0\expndtw0\kerning0
\ul \ulc0 Flashing\expnd0\expndtw0\kerning0
\ulnone \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \expnd0\expndtw0\kerning0
\ul Entity\
\pard\pardeftab720
\cf0 \expnd0\expndtw0\kerning0
\ulnone \'a0\'a0\'a0T \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0Thief\
\'a0\'a0\'a0O \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0Ogre\
\'a0\'a0\'a0Z \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0Zombie\
\'a0\'a0\'a0R \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0Rogue\
\
\'a0\expnd0\expndtw0\kerning0
\ul Player\expnd0\expndtw0\kerning0
\ulnone \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \expnd0\expndtw0\kerning0
\ul Facing Direction\expnd0\expndtw0\kerning0
\ulnone \
\'a0\'a0\'a0^ \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0North\
\'a0\'a0\'a0\\ \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0NE\
\'a0\'a0\'a0> \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0East\
\'a0\'a0\'a0/ \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0SE\
\'a0\'a0\'a0v \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0South\
\'a0\'a0\'a0\\ \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0SW\
\'a0\'a0\'a0< \'a0\'a0\'a0\'a0\'a0\'a0\'a0\'a0\'a0\'a0\'a0\'a0\'a0\'a0\'a0\'a0\'a0\'a0\'a0West\
\'a0\'a0\'a0/ \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0NW\
\
\pard\pardeftab720
\f0 \cf0 \expnd0\expndtw0\kerning0
Tiles in light are inverse. Entities are displayed only when lit and in field of view. The map is only visible when lit, i.e lamp is on or standing next to a torch.\
\
\pard\pardeftab720
\b\fs28 \cf0 \expnd0\expndtw0\kerning0
\ul \ulc0 Interaction\
\pard\pardeftab720
\f1\b0\fs24 \cf0 \expnd0\expndtw0\kerning0
\ulc0 Keyboard commands\expnd0\expndtw0\kerning0
\ulnone \'a0\'a0\'a0\'a0 \expnd0\expndtw0\kerning0
\ul Action\
\pard\pardeftab720
\cf0 \expnd0\expndtw0\kerning0
\ulnone \'a0\'a0\'a0Q \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 Run (Quick)\
\'a0\'a0\'a0W up-arrow \'a0 \'a0 \'a0 \'a0 \'a0 Forward\
\'a0\'a0\'a0S down-arrow \'a0 \'a0 \'a0 \'a0 Backward\
\'a0\'a0\'a0A left-arrow \'a0 \'a0 \'a0 \'a0 Turn left\
\'a0\'a0\'a0D right-arrow \'a0 \'a0 \'a0 Turn right\
\'a0\'a0\'a0I \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 Move N\
\'a0\'a0\'a0J \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 Move W\
\'a0\'a0\'a0K \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 Move E\
\'a0\'a0\'a0M \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 Move S\
\'a0\'a0\'a0< , \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 Turn lamp down\
\'a0\'a0\'a0> . \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 Turn lamp up/on\
\'a0\'a0\'a0O \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 Turn lamp off\
\'a0\'a0\'a0Space-bar \'a0 \'a0 \'a0 \'a0 \'a0 \'a0Open door\
\'a0\'a0\'a0Return \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 Pick up item\
\'a0\'a0\'a0X \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 \'a0 Exit (die)\
\pard\pardeftab720
\f0 \cf0 \expnd0\expndtw0\kerning0
\
Whenever you and an enemy end up on the same tile, battle commences. As you win fights, your skill increases, improving your attack effectiveness. As you advance through the catacombs, the enemies become more powerful. You will need to replenish health and energy with mana. Don't forget, the alternative to fighting is stealth in the darkness. During battle, you have the option to run. If you have low energy, you won't get very far. Also, when fighting, you get turned around so you can't depend on the direction you were facing before fighting. Running ('Q'uick) will get you away from enemies but will use much more energy.\
\
If you should die, restart the game by typing:\
\pard\pardeftab720
\f1 \cf0 \expnd0\expndtw0\kerning0
+rogue
\f2 \
\pard\pardeftab720
\f0 \cf0 \expnd0\expndtw0\kerning0
\
\pard\pardeftab720
\b\fs28 \cf0 \expnd0\expndtw0\kerning0
\ul \ulc0 Map Levels\
\pard\pardeftab720
\b0\fs24 \cf0 \expnd0\expndtw0\kerning0
\ulnone Level maps are up to 62x62 in size (plus a wall boundary for an effective 64x64 map size). They can be smaller than this. The game will end when it tries to load an non-existent level. Levels start at file name \'93LEVEL0\'93 and can go all the way to \'93LEVEL9\'93, but must be sequential.\
\
There are two levels included on the disk, and an empty level for you to use as a template.\'a0You\'a0can edit the map levels, and add your own. They are simple ASCII text files. The included sandbox editor can edit the maps right on the disk. type:\
\
\pard\pardeftab720
\f1 \cf0 \expnd0\expndtw0\kerning0
-sandbox level.empty
\f2 \
\pard\pardeftab720
\f0 \cf0 \expnd0\expndtw0\kerning0
\
after exiting from ROGUE. Make your changes and save it as LEVEL0" to "LEVEL9". The next free level is currently "LEVEL2". You may also edit an existing level:\
\
\pard\pardeftab720
\f1 \cf0 \expnd0\expndtw0\kerning0
-sandbox level0
\f2 \
\pard\pardeftab720
\f0 \cf0 \expnd0\expndtw0\kerning0
\
for instance.\
\
}

View File

@ -63,7 +63,7 @@ end
//
// Plot pixel
//
export asm dgrPlot(buff, x, y)
export asm dgrPlot(buff, x, y)#0
; GET BUFFER ADDRESS
STX ESP
LDA ESTKL+2,X
@ -90,12 +90,13 @@ asm _dgrPlotPix
LDX ESP
INX
INX
INX
RTS
end
//
// Plot horizontal row of pixels
//
export asm dgrHLin(buff, x1, x2, y)
export asm dgrHLin(buff, x1, x2, y)#0
; GET BUFFER ADDRESS
STX ESP
LDA ESTKL+3,X
@ -130,12 +131,13 @@ asm _dgrHLinPix
INX
INX
INX
INX
RTS
end
//
// Plot horizontal row of pixels
//
export asm dgrVLin(buff, x, y1, y2)
export asm dgrVLin(buff, x, y1, y2)#0
; GET BUFFER ADDRESS
STX ESP
LDA ESTKL+3,X
@ -168,13 +170,14 @@ asm _dgrVLinPix
BEQ -
INX
INX
INX
INX
RTS
end
//
// Draw sprite
//
export asm dgrBLT(buff, x, y, width, height, src)
export asm dgrBLT(buff, x, y, width, height, src)#0
LDA ESTKL,X ; SPRITE
STA SRCL
LDA ESTKH,X
@ -206,8 +209,9 @@ export asm dgrBLT(buff, x, y, width, height, src)
CLC
ADC ESTKL+2,X ; WIDTH
STA SRCL
BCC +++
INC SRCH
LDA SRCH
ADC #$00
STA SRCH
BNE +++
+ AND #$FE
TAY
@ -253,6 +257,7 @@ asm _dgrBLTPix
INX
INX
INX
INX
RTS
end
//
@ -267,10 +272,12 @@ asm _dgrSetPix
end
asm _dgrSetEvnEvn
; EVEN PIXEL
LDA $2000,X
AND #$0F
STA TMP
JSR $0100 ; LDA AUX (DST),Y
EOR $2000,X
AND #$F0
EOR $2000,X
ORA TMP
STA $C005 ; WRITE AUX MEM
STA (GBASE),Y
STA $C004 ; WRITE MAIN MEM
@ -278,10 +285,12 @@ asm _dgrSetEvnEvn
end
asm _dgrSetEvnOdd
; ODD PIXEL
+ LDA (GBASE),Y
EOR $1000,X
+ LDA $1000,X
AND #$0F
STA TMP
LDA (GBASE),Y
AND #$F0
EOR $1000,X
ORA TMP
STA (GBASE),Y
RTS
; ODD ROW
@ -291,10 +300,12 @@ asm _dgrSetEvnOdd
end
asm _dgrSetOddEvn
; EVEN PIXEL
LDA $2000,X
AND #$F0
STA TMP
JSR $0100 ; LDA AUX (DST),Y
EOR $2000,X
AND #$0F
EOR $2000,X
ORA TMP
STA $C005 ; WRITE AUX MEM
STA (GBASE),Y
STA $C004 ; WRITE MAIN MEM
@ -302,10 +313,12 @@ asm _dgrSetOddEvn
end
asm _dgrSetOddOdd
; ODD PIXEL
+++ LDA (GBASE),Y
EOR $1000,X
+++ LDA $1000,X
AND #$F0
STA TMP
LDA (GBASE),Y
AND #$0F
EOR $1000,X
ORA TMP
STA (GBASE),Y
RTS
end
@ -318,7 +331,7 @@ end
//
// Draw 8x8 tile (forced to 2x2 block address)
//
export asm dgrTile(buff, x, y, src)
export asm dgrTile(buff, x, y, src)#0
STX ESP
LDA ESTKL,X ; TILE
STA SRCL
@ -349,8 +362,9 @@ export asm dgrTile(buff, x, y, src)
LDA SRCL ; SKIP TO NEXT ROW
ADC #$07 ; CARRY = 1
STA SRCL
BCC +++
INC SRCH
LDA SRCH
ADC #$00
STA SRCH
BNE +++
+ AND #$FE
TAY
@ -398,14 +412,15 @@ export asm dgrTile(buff, x, y, src)
++++ INX
INX
INX
INX
RTS
end
//
// Draw a string of tiles
//
export asm dgrTileStr(buff, x, y, tilestr, strlen, tilebuff)
DEX
export asm dgrTileStr(buff, x, y, tilestr, strlen, tilebuff)#0
- DEX
DEX
DEX
DEX
LDA ESTKL+9,X ; BUFF
@ -423,13 +438,13 @@ export asm dgrTileStr(buff, x, y, tilestr, strlen, tilebuff)
end
asm _dgrTileTile
JSR $5000
LDA ESTKL+5,X ; UPDATE X COORD
LDA ESTKL+4,X ; UPDATE X COORD
CLC
ADC #$08
CMP #80 ; OFF RIGHT SIDE
BPL +
STA ESTKL+5,X
DEC ESTKL+2,X ; DEC STRLEN
STA ESTKL+4,X
DEC ESTKL+1,X ; DEC STRLEN
BNE -
+ INX
INX
@ -442,7 +457,7 @@ end
//
// Draw a string of tiles
//
export asm dgrFill(buff, x, y, tile)
export asm dgrFill(buff, x, y, tile)#0
LDA ESTKL+2,X
AND #$0F
STA ESTKL+2,X
@ -458,8 +473,8 @@ export asm dgrFill(buff, x, y, tile)
SEC
SBC ESTKL+1,X
STA ESTKL+1,X
DEX
- DEX
DEX
DEX
DEX
LDA ESTKL+7,X ; BUFF
@ -477,18 +492,18 @@ export asm dgrFill(buff, x, y, tile)
end
asm _dgrFillTile
JSR $5000
LDA ESTKL+3,X ; UPDATE X COORD
CLC
ADC #$08
STA ESTKL+3,X
CMP #80 ; OFF RIGHT SIDE?
BMI -
LDA ESTKH+3,X ; RESTORE X COORD
STA ESTKL+3,X
LDA ESTKL+2,X ; UPDATE Y COORD
LDA ESTKL+2,X ; UPDATE X COORD
CLC
ADC #$08
STA ESTKL+2,X
CMP #80 ; OFF RIGHT SIDE?
BMI -
LDA ESTKH+2,X ; RESTORE X COORD
STA ESTKL+2,X
LDA ESTKL+1,X ; UPDATE Y COORD
CLC
ADC #$08
STA ESTKL+1,X
CMP #48 ; OFF BOTTOM?
BMI -
INX
@ -500,8 +515,7 @@ end
//
// Wait for VLB
//
asm vlbWait
DEX
asm vlbWait#0
- LDA $C019
BMI -
- LDA $C019
@ -511,7 +525,7 @@ end
//
// Set double lores graphics, return draw buffer
//
export def dgrMode
export def dgrMode#1
^showlores
^showfull
^showgraphics
@ -520,24 +534,24 @@ export def dgrMode
^show80 = 0
// ^mapaux = 0
^an3on
return 1
return 1
end
//
// Set text mode
//
export def txtMode
export def txtMode#0
^showtext
^showpage1
^ena80 = 0
^show40 = 0
^mapmain = 0
^an3on
return call($FC58, 0, 0, 0, 0) // home()
call($FC58, 0, 0, 0, 0) // home()
end
//
// Set display page, return other page
//
export def dgrShow(page)
export def dgrShow(page)#1
page = page & 1
^(showpage1 + page)
return page ^ 1
@ -545,13 +559,13 @@ end
//
// Set color for cear & plot routines
//
export def dgrColor(clr)
export def dgrColor(clr)#0
^$30 = clr & $0F
end
//
// Draw line
//
export def dgrLine(buff, x1, y1, x2, y2)
export def dgrLine(buff, x1, y1, x2, y2)#0
byte dx, dy, dx2, dy2, pp
word sx, sy, err, dd2
@ -636,12 +650,12 @@ end
//
// Clear the buffer
//
export def dgrClear(buff, clr)
export def dgrClear(buff, clr)#0
byte[32] clrtile
clr = evnclr[clr&$0F] | (oddclr[clr&$0F] << 8)
memset(@clrtile, clr, 32)
return dgrFill(buff, 0, 0, @clrtile)
dgrFill(buff, 0, 0, @clrtile)
end
//
// Make sure we are a 128K //e or //c
@ -655,16 +669,16 @@ fin
//
// Assembly fixups
//
_dgrPlotPix:1 = @_dgrSetPix
_dgrHLinPix:1 = @_dgrSetPix
_dgrVLinPix:1 = @_dgrSetPix
_dgrBLTPix:1 = @_dgrSetPix
_dgrTileTile:1 = @dgrTile
_dgrFillTile:1 = @dgrTile
_dgrSetEvnEvn:1 = @evnclr
_dgrSetEvnOdd:1 = @oddclr
_dgrSetOddEvn:1 = @evnclr
_dgrSetOddOdd:1 = @oddclr
*(@_dgrPlotPix):1 = @_dgrSetPix
*(@_dgrHLinPix):1 = @_dgrSetPix
*(@_dgrVLinPix):1 = @_dgrSetPix
*(@_dgrBLTPix):1 = @_dgrSetPix
*(@_dgrTileTile):1 = @dgrTile
*(@_dgrFillTile):1 = @dgrTile
*(@_dgrSetEvnEvn):1 = @evnclr
*(@_dgrSetEvnOdd):1 = @oddclr
*(@_dgrSetOddEvn):1 = @evnclr
*(@_dgrSetOddOdd):1 = @oddclr
// Put read AUX mem routine in scary location
memcpy($0100, @auxRead, 9)
done

View File

@ -220,19 +220,19 @@ $(DGRTEST): samplesrc/dgrtest.pla $(PLVM02) $(PLASM)
acme --setpc 4094 -o $(DGRTEST) samplesrc/dgrtest.a
$(ROGUE): samplesrc/rogue.pla $(PLVM02) $(PLASM)
./$(PLASM) -AM < samplesrc/rogue.pla > samplesrc/rogue.a
./$(PLASM) -AMO < samplesrc/rogue.pla > samplesrc/rogue.a
acme --setpc 4094 -o $(ROGUE) samplesrc/rogue.a
$(ROGUEIO): samplesrc/rogue.io.pla $(PLVM02) $(PLASM)
./$(PLASM) -AM < samplesrc/rogue.io.pla > samplesrc/rogue.io.a
./$(PLASM) -AMO < samplesrc/rogue.io.pla > samplesrc/rogue.io.a
acme --setpc 4094 -o $(ROGUEIO) samplesrc/rogue.io.a
$(ROGUECOMBAT): samplesrc/rogue.combat.pla $(PLVM02) $(PLASM)
./$(PLASM) -AM < samplesrc/rogue.combat.pla > samplesrc/rogue.combat.a
./$(PLASM) -AMO < samplesrc/rogue.combat.pla > samplesrc/rogue.combat.a
acme --setpc 4094 -o $(ROGUECOMBAT) samplesrc/rogue.combat.a
$(ROGUEMAP): samplesrc/rogue.map.pla $(PLVM02) $(PLASM)
./$(PLASM) -AM < samplesrc/rogue.map.pla > samplesrc/rogue.map.a
./$(PLASM) -AMO < samplesrc/rogue.map.pla > samplesrc/rogue.map.a
acme --setpc 4094 -o $(ROGUEMAP) samplesrc/rogue.map.a
$(HGR1): samplesrc/hgr1.pla samplesrc/hgr1test.pla $(PLVM02) $(PLASM)

View File

@ -1,7 +1,18 @@
import dgr
word[] dgrbuff
predef drgPlot, dgrHLin, dgrVLin, dgrBLT, dgrTile, dgrTileStr, dgrFill
predef dgrMode, txtMode, dgrShow, dgrColor, dgrLine, dgrClear
predef dgrPlot(buff, x, y)#0
predef dgrHLin(buff, x1, x2, y)#0
predef dgrVLin(buff, x, y1, y2)#0
predef dgrBLT(buff, x, y, width, height, src)#0
predef dgrTile(buff, x, y, src)#0
predef dgrTileStr(buff, x, y, tilestr, strlen, tilebuff)#0
predef dgrFill(buff, x, y, tile)#0
predef dgrMode#1
predef txtMode#0
predef dgrShow(page)#1
predef dgrColor(clr)#0
predef dgrLine(buff, x1, y1, x2, y2)#0
predef dgrClear(buff, clr)#0
end
byte[] sprite1 = $80,$80,$00,$00,$00,$00,$80,$80
@ -21,10 +32,10 @@ byte[] = $0A,$05,$0A,$05,$0A,$05,$0A,$00
//
// Test routine
//
def dgrTest
def dgrTest#0
byte b, l, k
word i, j, ii, ij
b = dgrMode()
for k = 15 downto 0
dgrClear(dgrbuff[0], k)
@ -61,4 +72,4 @@ def dgrTest
end
dgrTest
done
done

View File

@ -37,7 +37,7 @@ word ptr
//
def tens(start)
word i, pptr
i = start
pptr = @print
repeat
@ -76,10 +76,16 @@ def nums(range)
puti(array[0]);putln
puti(array[1]);putln
end
def printfunc(a, b, lambda)#0
puts("func(a,b)=")
puti(lambda(a,b))
putln
end
export def main(range)
byte a
word lambda
a = 10
nums(*range)
tens(*range*10)
ascii
@ -110,7 +116,16 @@ export def main(range)
putc('?')
wend
putln
printfunc(1, 2, &(a,b) a+b)
printfunc(1, 2, &(a,b) (a-b))
lambda = &(x,y) x * y
puti(lambda(2,3));putln
end
def dummy(zz)#0
puts("dummy func"); putln
end
puti(array[0]);putc(' ')
puti(array[1]);putc(' ')
puti(array[2]);putc(' ')

View File

@ -1,34 +1,41 @@
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "plasm.h"
/*
* Symbol table and fixup information.
*/
#define ID_LEN 32
static int consts = 0;
static int externs = 0;
static int globals = 0;
static int locals = 0;
static int predefs = 0;
static int defs = 0;
static int asmdefs = 0;
static int codetags = 1; // Fix check for break_tag and cont_tag
static int fixups = 0;
static int consts = 0;
static int externs = 0;
static int globals = 0;
static int locals = 0;
static int localsize = 0;
static int predefs = 0;
static int defs = 0;
static int asmdefs = 0;
static int codetags = 1; // Fix check for break_tag and cont_tag
static int fixups = 0;
static char idconst_name[1024][ID_LEN+1];
static int idconst_value[1024];
static char idglobal_name[1024][ID_LEN+1];
static int idglobal_type[1024];
static int idglobal_tag[1024];
static int localsize = 0;
static char idlocal_name[128][ID_LEN+1];
static int idlocal_type[128];
static int idlocal_offset[128];
static char fixup_size[2048];
static int fixup_type[2048];
static int fixup_tag[2048];
static t_opseq optbl[256];
static int savelocalsize = 0;
static int savelocals = 0;
static char savelocal_name[128][ID_LEN+1];
static int savelocal_type[128];
static int savelocal_offset[128];
static t_opseq optbl[2048];
static t_opseq *freeop_lst = &optbl[0];
static t_opseq *pending_seq = 0;
#define FIXUP_BYTE 0x00
#define FIXUP_WORD 0x80
int id_match(char *name, int len, char *id)
@ -166,6 +173,24 @@ void idlocal_reset(void)
locals = 0;
localsize = 0;
}
void idlocal_save(void)
{
savelocals = locals;
savelocalsize = localsize;
memcpy(savelocal_name, idlocal_name, locals*(ID_LEN+1));
memcpy(savelocal_type, idlocal_type, locals*sizeof(int));
memcpy(savelocal_offset, idlocal_offset, locals*sizeof(int));
locals = 0;
localsize = 0;
}
void idlocal_restore(void)
{
locals = savelocals;
localsize = savelocalsize;
memcpy(idlocal_name, savelocal_name, locals*(ID_LEN+1));
memcpy(idlocal_type, savelocal_type, locals*sizeof(int));
memcpy(idlocal_offset, savelocal_offset, locals*sizeof(int));
}
int idfunc_add(char *name, int len, int type, int tag)
{
if (globals > 1024)
@ -466,6 +491,18 @@ void emit_idfunc(int tag, int type, char *name, int is_bytecode)
printf("\tJSR\tINTERP\n");
}
}
void emit_lambdafunc(int tag, char *name, int cparams, t_opseq *lambda_seq)
{
emit_idfunc(tag, DEF_TYPE, name, 1);
if (cparams)
printf("\t%s\t$58,$%02X,$%02X\t\t; ENTER\t%d,%d\n", DB, 0, cparams, 0, cparams);
emit_seq(lambda_seq);
emit_pending_seq();
if (cparams)
printf("\t%s\t$5A\t\t\t; LEAVE\n", DB);
else
printf("\t%s\t$5C\t\t\t; RET\n", DB);
}
void emit_idconst(char *name, int value)
{
printf("\t\t\t\t\t; %s = %d\n", name, value);
@ -536,10 +573,12 @@ int emit_data(int vartype, int consttype, long constval, int constsize)
}
void emit_codetag(int tag)
{
emit_pending_seq();
printf("_B%03d%c\n", tag, LBL);
}
void emit_const(int cval)
{
emit_pending_seq();
if (cval == 0x0000)
printf("\t%s\t$00\t\t\t; ZERO\n", DB);
else if ((cval & 0xFF00) == 0x0000)
@ -652,17 +691,27 @@ void emit_saw(int tag, int offset, int type)
}
void emit_dab(int tag, int offset, int type)
{
int fixup = fixup_new(tag, type, FIXUP_WORD);
char *taglbl = tag_string(tag, type);
printf("\t%s\t$7C\t\t\t; DAB\t%s+%d\n", DB, taglbl, offset);
printf("_F%03d%c\t%s\t%s+%d\t\t\n", fixup, LBL, DW, type & EXTERN_TYPE ? "0" : taglbl, offset);
if (type)
{
int fixup = fixup_new(tag, type, FIXUP_WORD);
char *taglbl = tag_string(tag, type);
printf("\t%s\t$7C\t\t\t; DAB\t%s+%d\n", DB, taglbl, offset);
printf("_F%03d%c\t%s\t%s+%d\t\t\n", fixup, LBL, DW, type & EXTERN_TYPE ? "0" : taglbl, offset);
}
else
printf("\t%s\t$7C,$%02X,$%02X\t\t; DAB\t%d\n", DB, offset&0xFF,(offset>>8)&0xFF, offset);
}
void emit_daw(int tag, int offset, int type)
{
int fixup = fixup_new(tag, type, FIXUP_WORD);
char *taglbl = tag_string(tag, type);
printf("\t%s\t$7E\t\t\t; DAW\t%s+%d\n", DB, taglbl, offset);
printf("_F%03d%c\t%s\t%s+%d\t\t\n", fixup, LBL, DW, type & EXTERN_TYPE ? "0" : taglbl, offset);
if (type)
{
int fixup = fixup_new(tag, type, FIXUP_WORD);
char *taglbl = tag_string(tag, type);
printf("\t%s\t$7E\t\t\t; DAW\t%s+%d\n", DB, taglbl, offset);
printf("_F%03d%c\t%s\t%s+%d\t\t\n", fixup, LBL, DW, type & EXTERN_TYPE ? "0" : taglbl, offset);
}
else
printf("\t%s\t$7E,$%02X,$%02X\t\t; DAW\t%d\n", DB, offset&0xFF,(offset>>8)&0xFF, offset);
}
void emit_localaddr(int index)
{
@ -695,6 +744,7 @@ void emit_brtru(int tag)
}
void emit_brnch(int tag)
{
emit_pending_seq();
printf("\t%s\t$50\t\t\t; BRNCH\t_B%03d\n", DB, tag);
printf("\t%s\t_B%03d-*\n", DW, tag);
}
@ -705,16 +755,19 @@ void emit_breq(int tag)
}
void emit_brne(int tag)
{
emit_pending_seq();
printf("\t%s\t$3E\t\t\t; BRNE\t_B%03d\n", DB, tag);
printf("\t%s\t_B%03d-*\n", DW, tag);
}
void emit_brgt(int tag)
{
emit_pending_seq();
printf("\t%s\t$38\t\t\t; BRGT\t_B%03d\n", DB, tag);
printf("\t%s\t_B%03d-*\n", DW, tag);
}
void emit_brlt(int tag)
{
emit_pending_seq();
printf("\t%s\t$3A\t\t\t; BRLT\t_B%03d\n", DB, tag);
printf("\t%s\t_B%03d-*\n", DW, tag);
}
@ -739,6 +792,7 @@ void emit_ical(void)
}
void emit_leave(void)
{
emit_pending_seq();
if (localsize)
printf("\t%s\t$5A\t\t\t; LEAVE\n", DB);
else
@ -746,6 +800,7 @@ void emit_leave(void)
}
void emit_ret(void)
{
emit_pending_seq();
printf("\t%s\t$5C\t\t\t; RET\n", DB);
}
void emit_enter(int cparams)
@ -769,6 +824,7 @@ void emit_pull_exp(void)
}
void emit_drop(void)
{
emit_pending_seq();
printf("\t%s\t$30\t\t\t; DROP\n", DB);
}
void emit_dup(void)
@ -777,6 +833,7 @@ void emit_dup(void)
}
int emit_unaryop(t_token op)
{
emit_pending_seq();
switch (op)
{
case NEG_TOKEN:
@ -808,6 +865,7 @@ int emit_unaryop(t_token op)
}
int emit_op(t_token op)
{
emit_pending_seq();
switch (op)
{
case MUL_TOKEN:
@ -908,12 +966,69 @@ void release_seq(t_opseq *seq)
freeop_lst = op;
}
}
/*
* Indicate if an address is (or might be) memory-mapped hardware; used to avoid
* optimising away accesses to such addresses.
*/
int is_hardware_address(int addr)
{
// TODO: I think this is reasonable for Apple hardware but I'm not sure.
// It's a bit too strong for Acorn hardware but code is unlikely to try to
// read from high addresses anyway, so there's no real harm in not
// optimising such accesses anyway.
return addr >= 0xC000;
}
/*
* Replace all but the first of a series of identical load opcodes by DUP. This
* doesn't reduce the number of opcodes but does reduce their size in bytes.
* This is only called on the second optimisation pass because the DUP opcodes
* may inhibit other peephole optimisations which are more valuable.
*/
int try_dupify(t_opseq *op)
{
int crunched = 0;
t_opseq *opn = op->nextop;
for (; opn; opn = opn->nextop)
{
if (op->code != opn->code)
return crunched;
switch (op->code)
{
case CONST_CODE:
if (op->val != opn->val)
return crunched;
break;
case LADDR_CODE:
case LLB_CODE:
case LLW_CODE:
if (op->offsz != opn->offsz)
return crunched;
break;
case GADDR_CODE:
case LAB_CODE:
case LAW_CODE:
if ((op->tag != opn->tag) || (op->offsz != opn->offsz) ||
(op->type != opn->type))
return crunched;
break;
default:
return crunched;
}
opn->code = DUP_CODE;
crunched = 1;
}
return crunched;
}
/*
* Crunch sequence (peephole optimize)
*/
int crunch_seq(t_opseq **seq)
int crunch_seq(t_opseq **seq, int pass)
{
t_opseq *opnext, *opnextnext;
t_opseq *opnext, *opnextnext, *opprev = 0;
t_opseq *op = *seq;
int crunched = 0;
int freeops = 0;
@ -977,15 +1092,7 @@ int crunch_seq(t_opseq **seq)
break;
case BRFALSE_CODE:
if (op->val)
{
opnextnext = opnext->nextop; // Remove never taken branch
if (op == *seq)
*seq = opnextnext;
opnext->nextop = NULL;
release_seq(op);
opnext = opnextnext;
crunched = 1;
}
freeops = -2; // Remove constant and never taken branch
else
{
op->code = BRNCH_CODE; // Always taken branch
@ -995,15 +1102,7 @@ int crunch_seq(t_opseq **seq)
break;
case BRTRUE_CODE:
if (!op->val)
{
opnextnext = opnext->nextop; // Remove never taken branch
if (op == *seq)
*seq = opnextnext;
opnext->nextop = NULL;
release_seq(op);
opnext = opnextnext;
crunched = 1;
}
freeops = -2; // Remove constant never taken branch
else
{
op->code = BRNCH_CODE; // Always taken branch
@ -1011,7 +1110,19 @@ int crunch_seq(t_opseq **seq)
freeops = 1;
}
break;
case CONST_CODE: // Collapse constant operation
case NE_CODE:
if (!op->val)
freeops = -2; // Remove ZERO:ISNE
break;
case EQ_CODE:
if (!op->val)
{
op->code = LOGIC_NOT_CODE;
freeops = 1;
}
break;
case CONST_CODE:
// Collapse constant operation
if ((opnextnext = opnext->nextop))
switch (opnextnext->code)
{
@ -1088,6 +1199,9 @@ int crunch_seq(t_opseq **seq)
freeops = 2;
break;
}
// End of collapse constant operation
if ((pass > 0) && (freeops == 0) && (op->val != 0))
crunched = try_dupify(op);
break; // CONST_CODE
case BINARY_CODE(MUL_TOKEN):
for (shiftcnt = 0; shiftcnt < 16; shiftcnt++)
@ -1148,6 +1262,8 @@ int crunch_seq(t_opseq **seq)
freeops = 1;
break;
}
if ((pass > 0) && (freeops == 0))
crunched = try_dupify(op);
break; // LADDR_CODE
case GADDR_CODE:
switch (opnext->code)
@ -1188,7 +1304,54 @@ int crunch_seq(t_opseq **seq)
freeops = 1;
break;
}
if ((pass > 0) && (freeops == 0))
crunched = try_dupify(op);
break; // GADDR_CODE
case LLB_CODE:
if (pass > 0)
crunched = try_dupify(op);
break; // LLB_CODE
case LLW_CODE:
// LLW [n]:CB 8:SHR -> LLB [n+1]
if ((opnext->code == CONST_CODE) && (opnext->val == 8))
{
if ((opnextnext = opnext->nextop))
{
if (opnextnext->code == SHR_CODE)
{
op->code = LLB_CODE;
op->offsz++;
freeops = 2;
break;
}
}
}
if ((pass > 0) && (freeops == 0))
crunched = try_dupify(op);
break; // LLW_CODE
case LAB_CODE:
if ((pass > 0) && (op->type || !is_hardware_address(op->offsz)))
crunched = try_dupify(op);
break; // LAB_CODE
case LAW_CODE:
// LAW x:CB 8:SHR -> LAB x+1
if ((opnext->code == CONST_CODE) && (opnext->val == 8))
{
if ((opnextnext = opnext->nextop))
{
if (opnextnext->code == SHR_CODE)
{
op->code = LAB_CODE;
op->offsz++;
freeops = 2;
break;
}
}
}
if ((pass > 0) && (freeops == 0) &&
(op->type || !is_hardware_address(op->offsz)))
crunched = try_dupify(op);
break; // LAW_CODE
case LOGIC_NOT_CODE:
switch (opnext->code)
{
@ -1204,10 +1367,64 @@ int crunch_seq(t_opseq **seq)
break;
}
break; // LOGIC_NOT_CODE
case SLB_CODE:
if ((opnext->code == LLB_CODE) && (op->offsz == opnext->offsz))
{
op->code = DLB_CODE;
freeops = 1;
}
break; // SLB_CODE
case SLW_CODE:
if ((opnext->code == LLW_CODE) && (op->offsz == opnext->offsz))
{
op->code = DLW_CODE;
freeops = 1;
}
break; // SLW_CODE
case SAB_CODE:
if ((opnext->code == LAB_CODE) && (op->tag == opnext->tag) &&
(op->offsz == opnext->offsz) && (op->type == opnext->type))
{
op->code = DAB_CODE;
freeops = 1;
}
break; // SAB_CODE
case SAW_CODE:
if ((opnext->code == LAW_CODE) && (op->tag == opnext->tag) &&
(op->offsz == opnext->offsz) && (op->type == opnext->type))
{
op->code = DAW_CODE;
freeops = 1;
}
break; // SAW_CODE
}
//
// Free up crunched ops
//
// Free up crunched ops. If freeops is positive we free up that many ops
// *after* op; if it's negative, we free up abs(freeops) ops *starting
// with* op.
if (freeops < 0)
{
freeops = -freeops;
// If op is at the start of the sequence, we treat this as a special
// case.
if (op == *seq)
{
for (; freeops > 0; --freeops)
{
opnext = op->nextop;
release_op(op);
op = *seq = opnext;
}
crunched = 1;
}
// Otherwise we just move op back to point to the previous op and
// let the following loop remove the required number of ops.
else
{
op = opprev;
opnext = op->nextop;
}
}
while (freeops)
{
op->nextop = opnext->nextop;
@ -1217,6 +1434,7 @@ int crunch_seq(t_opseq **seq)
crunched = 1;
freeops--;
}
opprev = op;
op = opnext;
}
return (crunched);
@ -1261,18 +1479,60 @@ t_opseq *cat_seq(t_opseq *seq1, t_opseq *seq2)
return (seq1);
}
/*
* Emit a sequence of ops
* Emit a sequence of ops (into the pending sequence)
*/
int emit_seq(t_opseq *seq)
{
t_opseq *op;
int emitted = 0;
int string = 0;
for (op = seq; op; op = op->nextop)
{
if (op->code == STR_CODE)
string = 1;
emitted++;
}
pending_seq = cat_seq(pending_seq, seq);
// The source code comments in the output are much more logical if we don't
// merge multiple sequences together. There's no value in doing this merging
// if we're not optimizing, and we optionally allow it to be prevented even
// when we are optimizing by specifing the -N (NO_COMBINE) flag.
//
// We must also force output if the sequence includes a CS opcode, as the
// associated 'constant' is only temporarily valid.
if (!(outflags & OPTIMIZE) || (outflags & NO_COMBINE) || string)
return emit_pending_seq();
return (emitted);
}
/*
* Emit the pending sequence
*/
int emit_pending_seq()
{
// This is called by some of the emit_*() functions to ensure that any
// pending ops are emitted before they emit their own op when they are
// called from the parser. However, this function itself calls some of those
// emit_*() functions to emit instructions from the pending sequence, which
// would cause an infinite loop if we weren't careful. We therefore set
// pending_seq to null on entry and work with a local copy, so if this
// function calls back into itself it is a no-op.
if (!pending_seq)
return 0;
t_opseq *local_pending_seq = pending_seq;
pending_seq = 0;
t_opseq *op;
int emitted = 0;
if (outflags & OPTIMIZE)
while (crunch_seq(&seq));
while (seq)
{
op = seq;
int pass;
for (pass = 0; pass < 2; pass++)
while (crunch_seq(&local_pending_seq, pass));
}
while (local_pending_seq)
{
op = local_pending_seq;
switch (op->code)
{
case NEG_CODE:
@ -1402,7 +1662,7 @@ int emit_seq(t_opseq *seq)
return (0);
}
emitted++;
seq = seq->nextop;
local_pending_seq = local_pending_seq->nextop;
/*
* Free this op
*/

View File

@ -8,31 +8,31 @@ typedef struct _opseq {
} t_opseq;
#define UNARY_CODE(tkn) ((tkn)|0x0100)
#define BINARY_CODE(tkn) ((tkn)|0x0200)
#define NEG_CODE 0x0100|NEG_TOKEN
#define COMP_CODE 0x0100|COMP_TOKEN
#define LOGIC_NOT_CODE 0x0100|LOGIC_NOT_TOKEN
#define INC_CODE 0x0100|INC_TOKEN
#define DEC_CODE 0x0100|DEC_TOKEN
#define BPTR_CODE 0x0100|BPTR_TOKEN
#define WPTR_CODE 0x0100|WPTR_TOKEN
#define MUL_CODE 0x0200|MUL_TOKEN
#define DIV_CODE 0x0200|DIV_TOKEN
#define MOD_CODE 0x0200|MOD_TOKEN
#define ADD_CODE 0x0200|ADD_TOKEN
#define SUB_CODE 0x0200|SUB_TOKEN
#define SHL_CODE 0x0200|SHL_TOKEN
#define SHR_CODE 0x0200|SHR_TOKEN
#define AND_CODE 0x0200|AND_TOKEN
#define OR_CODE 0x0200|OR_TOKEN
#define EOR_CODE 0x0200|EOR_TOKEN
#define EQ_CODE 0x0200|EQ_TOKEN
#define NE_CODE 0x0200|NE_TOKEN
#define GE_CODE 0x0200|GE_TOKEN
#define LT_CODE 0x0200|LT_TOKEN
#define GT_CODE 0x0200|GT_TOKEN
#define LE_CODE 0x0200|LE_TOKEN
#define LOGIC_OR_CODE 0x0200|LOGIC_OR_TOKEN
#define LOGIC_AND_CODE 0x0200|LOGIC_AND_TOKEN
#define NEG_CODE (0x0100|NEG_TOKEN)
#define COMP_CODE (0x0100|COMP_TOKEN)
#define LOGIC_NOT_CODE (0x0100|LOGIC_NOT_TOKEN)
#define INC_CODE (0x0100|INC_TOKEN)
#define DEC_CODE (0x0100|DEC_TOKEN)
#define BPTR_CODE (0x0100|BPTR_TOKEN)
#define WPTR_CODE (0x0100|WPTR_TOKEN)
#define MUL_CODE (0x0200|MUL_TOKEN)
#define DIV_CODE (0x0200|DIV_TOKEN)
#define MOD_CODE (0x0200|MOD_TOKEN)
#define ADD_CODE (0x0200|ADD_TOKEN)
#define SUB_CODE (0x0200|SUB_TOKEN)
#define SHL_CODE (0x0200|SHL_TOKEN)
#define SHR_CODE (0x0200|SHR_TOKEN)
#define AND_CODE (0x0200|AND_TOKEN)
#define OR_CODE (0x0200|OR_TOKEN)
#define EOR_CODE (0x0200|EOR_TOKEN)
#define EQ_CODE (0x0200|EQ_TOKEN)
#define NE_CODE (0x0200|NE_TOKEN)
#define GE_CODE (0x0200|GE_TOKEN)
#define LT_CODE (0x0200|LT_TOKEN)
#define GT_CODE (0x0200|GT_TOKEN)
#define LE_CODE (0x0200|LE_TOKEN)
#define LOGIC_OR_CODE (0x0200|LOGIC_OR_TOKEN)
#define LOGIC_AND_CODE (0x0200|LOGIC_AND_TOKEN)
#define CONST_CODE 0x0300
#define STR_CODE 0x0301
#define LB_CODE 0x0302
@ -95,6 +95,7 @@ void emit_asm(char *s);
void emit_idlocal(char *name, int value);
void emit_idglobal(int value, int size, char *name);
void emit_idfunc(int tag, int type, char *name, int is_bytecode);
void emit_lambdafunc(int tag, char *name, int cparams, t_opseq *lambda_seq);
void emit_idconst(char *name, int value);
int emit_data(int vartype, int consttype, long constval, int constsize);
void emit_codetag(int tag);
@ -142,7 +143,8 @@ void emit_start(void);
void emit_rld(void);
void emit_esd(void);
void release_seq(t_opseq *seq);
int crunch_seq(t_opseq **seq);
int crunch_seq(t_opseq **seq, int pass);
t_opseq *gen_seq(t_opseq *seq, int opcode, long cval, int tag, int offsz, int type);
t_opseq *cat_seq(t_opseq *seq1, t_opseq *seq2);
int emit_seq(t_opseq *seq);
int emit_pending_seq();

View File

@ -1,11 +1,19 @@
#include <stdio.h>
#include <string.h>
#include "plasm.h"
#define LVALUE 0
#define RVALUE 1
#define LVALUE 0
#define RVALUE 1
#define MAX_LAMBDA 64
int infunc = 0, break_tag = 0, cont_tag = 0, stack_loop = 0;
long infuncvals = 0;
t_token prevstmnt;
static int lambda_num = 0;
static int lambda_cnt = 0;
static t_opseq *lambda_seq[MAX_LAMBDA];
static char lambda_id[MAX_LAMBDA][16];
static int lambda_tag[MAX_LAMBDA];
static int lambda_cparams[MAX_LAMBDA];
t_token binary_ops_table[] = {
/* Highest precedence */
MUL_TOKEN, DIV_TOKEN, MOD_TOKEN,
@ -338,6 +346,7 @@ int parse_const(long *value)
/*
* Normal expression parsing
*/
int parse_lambda(void);
t_opseq *parse_expr(t_opseq *codeseq, int *stackdepth);
t_opseq *parse_list(t_opseq *codeseq, int *stackdepth)
{
@ -446,6 +455,12 @@ t_opseq *parse_value(t_opseq *codeseq, int rvalue, int *stackdepth)
cfnvals = funcvals_cnt(type);
}
}
else if (scantoken == LAMBDA_TOKEN)
{
type |= CONST_TYPE;
value = parse_lambda();
valseq = gen_gbladr(NULL, value, FUNC_TYPE);
}
else if (scantoken == OPEN_PAREN_TOKEN)
{
if (!(valseq = parse_expr(NULL, stackdepth)))
@ -474,7 +489,7 @@ t_opseq *parse_value(t_opseq *codeseq, int rvalue, int *stackdepth)
valseq = cat_seq(parse_list(NULL, &value), valseq);
if (scantoken != CLOSE_PAREN_TOKEN)
{
parse_error("Missing closing parenthesis");
parse_error("Missing function call closing parenthesis");
return (NULL);
}
if (scan() == POUND_TOKEN)
@ -569,6 +584,11 @@ t_opseq *parse_value(t_opseq *codeseq, int rvalue, int *stackdepth)
type = (scantoken == PTRB_TOKEN) ? BPTR_TYPE : WPTR_TYPE;
if (!parse_const(&const_offset))
{
if (scantoken == EOL_TOKEN || scantoken == CLOSE_PAREN_TOKEN)
{
parse_error("Syntax");
return (NULL);
}
/*
* Setting type override for following operations
*/
@ -603,6 +623,11 @@ t_opseq *parse_value(t_opseq *codeseq, int rvalue, int *stackdepth)
: ((scantoken == DOT_TOKEN) ? BPTR_TYPE : WPTR_TYPE);
if (!parse_const(&const_offset))
{
if (scantoken == EOL_TOKEN || scantoken == CLOSE_PAREN_TOKEN)
{
parse_error("Syntax");
return (NULL);
}
/*
* Setting type override for following operations
*/
@ -728,6 +753,7 @@ t_opseq *parse_set(t_opseq *codeseq)
char *setptr = tokenstr;
int lparms = 0, rparms = 0;
int i;
int lambda_set = lambda_cnt;
t_opseq *setseq[16], *rseq = NULL;
while ((setseq[lparms] = parse_value(NULL, LVALUE, NULL)))
@ -742,6 +768,12 @@ t_opseq *parse_set(t_opseq *codeseq)
scan_rewind(tokenstr);
while (lparms--)
release_seq(setseq[lparms]);
while (lambda_cnt > lambda_set)
{
lambda_cnt--;
lambda_num--;
release_seq(lambda_seq[lambda_cnt]);
}
return (NULL);
}
rseq = parse_list(NULL, &rparms);
@ -1447,6 +1479,80 @@ int parse_mods(void)
emit_moddep(0, 0);
return (0);
}
int parse_lambda(void)
{
int func_tag;
int cfnparms;
char *expr;
if (!infunc)
{
parse_error("Lambda functions only allowed inside definitions");
return (0);
}
idlocal_save();
/*
* Parse parameters and return value count
*/
cfnparms = 0;
if (scan() == OPEN_PAREN_TOKEN)
{
do
{
if (scan() == ID_TOKEN)
{
cfnparms++;
idlocal_add(tokenstr, tokenlen, WORD_TYPE, 2);
scan();
}
} while (scantoken == COMMA_TOKEN);
if (scantoken != CLOSE_PAREN_TOKEN)
{
parse_error("Bad function parameter list");
return (0);
}
}
else
{
parse_error("Missing parameter list in lambda function");
return (0);
}
expr = scanpos;
if (scan_lookahead() == OPEN_PAREN_TOKEN)
{
/*
* Function call - parameters generate before call address
*/
scan();
lambda_seq[lambda_cnt] = parse_list(NULL, NULL);
if (scantoken != CLOSE_PAREN_TOKEN)
{
parse_error("Missing closing lambda function parenthesis");
return (0);
}
}
else
{
lambda_seq[lambda_cnt] = parse_expr(NULL, NULL);
scan_rewind(tokenstr);
}
sprintf(lambda_id[lambda_cnt], "_LAMBDA%04d", lambda_num++);
if (idglobal_lookup(lambda_id[lambda_cnt], strlen(lambda_id[lambda_cnt])) >= 0)
{
func_tag = lambda_tag[lambda_cnt];
idfunc_set(lambda_id[lambda_cnt], strlen(lambda_id[lambda_cnt]), DEF_TYPE | funcparms_type(cfnparms), func_tag); // Override any predef type & tag
}
else
{
func_tag = tag_new(DEF_TYPE);
lambda_tag[lambda_cnt] = func_tag;
lambda_cparams[lambda_cnt] = cfnparms;
idfunc_add(lambda_id[lambda_cnt], strlen(lambda_id[lambda_cnt]), DEF_TYPE | funcparms_type(cfnparms), func_tag);
}
lambda_cnt++;
idlocal_restore();
return (func_tag);
}
int parse_defs(void)
{
char c, *idstr;
@ -1469,6 +1575,7 @@ int parse_defs(void)
return (0);
}
emit_bytecode_seg();
lambda_cnt = 0;
bytecode = 1;
cfnparms = 0;
infuncvals = 1; // Defaut to one return value for compatibility
@ -1557,6 +1664,8 @@ int parse_defs(void)
emit_const(0);
emit_leave();
}
while (lambda_cnt--)
emit_lambdafunc(lambda_tag[lambda_cnt], lambda_id[lambda_cnt], lambda_cparams[lambda_cnt], lambda_seq[lambda_cnt]);
return (1);
}
else if (scantoken == ASM_TOKEN)

View File

@ -24,6 +24,9 @@ int main(int argc, char **argv)
case 'O':
outflags |= OPTIMIZE;
break;
case 'N':
outflags |= NO_COMBINE;
break;
case 'W':
outflags |= WARNINGS;
}

View File

@ -8,6 +8,7 @@
#define INIT (1<<4)
#define SYSFLAGS (1<<5)
#define WARNINGS (1<<6)
#define NO_COMBINE (1<<7)
extern int outflags;
#include "tokens.h"
#include "lex.h"

View File

@ -36,6 +36,8 @@ int idlocal_add(char *name, int len, int type, int size);
int idglobal_add(char *name, int len, int type, int size);
int id_add(char *name, int len, int type, int size);
void idlocal_reset(void);
void idlocal_save(void);
void idlocal_restore(void);
int idfunc_set(char *name, int len, int type, int tag);
int idfunc_add(char *name, int len, int type, int tag);
int idconst_add(char *name, int len, int value);

View File

@ -1,13 +1,3 @@
/*
* Copyright (C) 2015 The 8-Bit Bunch. Licensed under the Apache License, Version 1.1
* (the "License"); you may not use this file except in compliance with the License.
* You may obtain a copy of the License at <http://www.apache.org/licenses/LICENSE-1.1>.
* Unless required by applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
* ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
#define TOKEN(c) (0x80|(c))
#define IS_TOKEN(c) (0x80&(c))
/*
@ -91,6 +81,7 @@
#define NEG_TOKEN TOKEN('-')
#define COMP_TOKEN TOKEN('~')
#define LOGIC_NOT_TOKEN TOKEN('!')
#define LAMBDA_TOKEN TOKEN('&')
#define INC_TOKEN TOKEN('P')
#define DEC_TOKEN TOKEN('K')
#define BPTR_TOKEN TOKEN('^')

View File

@ -5,6 +5,7 @@
;* SYSTEM ROUTINES AND LOCATIONS
;*
;**********************************************************
SELFMODIFY = 1
;*
;* VM ZERO PAGE LOCATIONS
;*
@ -441,6 +442,17 @@ CS DEX
;*
;* LOAD VALUE FROM ADDRESS TAG
;*
!IF SELFMODIFY {
LB LDA ESTKL,X
STA LBLDA+1
LDA ESTKH,X
STA LBLDA+2
LBLDA LDA $FFFF
STA ESTKL,X
LDA #$00
STA ESTKH,X
JMP NEXTOP
} ELSE {
LB LDA ESTKL,X
STA TMPL
LDA ESTKH,X
@ -452,6 +464,7 @@ LB LDA ESTKL,X
STY ESTKH,X
LDY IPY
JMP NEXTOP
}
LW LDA ESTKL,X
STA TMPL
LDA ESTKH,X
@ -507,6 +520,20 @@ LLW +INC_IP
;*
;* LOAD VALUE FROM ABSOLUTE ADDRESS
;*
!IF SELFMODIFY {
LAB +INC_IP
LDA (IP),Y
STA LABLDA+1
+INC_IP
LDA (IP),Y
STA LABLDA+2
LABLDA LDA $FFFF
DEX
STA ESTKL,X
LDA #$00
STA ESTKH,X
JMP NEXTOP
} ELSE {
LAB +INC_IP
LDA (IP),Y
STA TMPL
@ -521,6 +548,7 @@ LAB +INC_IP
STY ESTKH,X
LDY IPY
JMP NEXTOP
}
LAW +INC_IP
LDA (IP),Y
STA TMPL
@ -540,6 +568,18 @@ LAW +INC_IP
;*
;* STORE VALUE TO ADDRESS
;*
!IF SELFMODIFY {
SB LDA ESTKL,X
STA SBSTA+1
LDA ESTKH,X
STA SBSTA+2
LDA ESTKL+1,X
SBSTA STA $FFFF
INX
; INX
; JMP NEXTOP
JMP DROP
} ELSE {
SB LDA ESTKL,X
STA TMPL
LDA ESTKH,X
@ -553,6 +593,7 @@ SB LDA ESTKL,X
; INX
; JMP NEXTOP
JMP DROP
}
SW LDA ESTKL,X
STA TMPL
LDA ESTKH,X
@ -620,6 +661,19 @@ DLW +INC_IP
;*
;* STORE VALUE TO ABSOLUTE ADDRESS
;*
!IF SELFMODIFY {
SAB +INC_IP
LDA (IP),Y
STA SABSTA+1
+INC_IP
LDA (IP),Y
STA SABSTA+2
LDA ESTKL,X
SABSTA STA $FFFF
; INX
; JMP NEXTOP
JMP DROP
} ELSE {
SAB +INC_IP
LDA (IP),Y
STA TMPL
@ -634,6 +688,7 @@ SAB +INC_IP
; INX
; JMP NEXTOP
JMP DROP
}
SAW +INC_IP
LDA (IP),Y
STA TMPL
@ -654,6 +709,17 @@ SAW +INC_IP
;*
;* STORE VALUE TO ABSOLUTE ADDRESS WITHOUT POPPING STACK
;*
!IF SELFMODIFY {
DAB +INC_IP
LDA (IP),Y
STA DABSTA+1
+INC_IP
LDA (IP),Y
STA DABSTA+2
LDA ESTKL,X
DABSTA STA $FFFF
JMP NEXTOP
} ELSE {
DAB +INC_IP
LDA (IP),Y
STA TMPL
@ -666,6 +732,7 @@ DAB +INC_IP
STA (TMP),Y
LDY IPY
JMP NEXTOP
}
DAW +INC_IP
LDA (IP),Y
STA TMPL

View File

@ -5,6 +5,7 @@
;* SYSTEM ROUTINES AND LOCATIONS
;*
;**********************************************************
SELFMODIFY = 0
;*
;* MONITOR SPECIAL LOCATIONS
;*
@ -195,9 +196,13 @@ DINTRP PLA
LDA PPH
STA IFPH
LDY #$00
!IF SELFMODIFY {
BEQ +
} ELSE {
LDA #>OPTBL
STA OPPAGE
JMP FETCHOP
}
IINTRP PLA
STA TMPL
PLA
@ -217,8 +222,12 @@ IINTRP PLA
STA IFPL
LDA PPH
STA IFPH
LDA #>OPTBL
+ LDA #>OPTBL
STA OPPAGE
!IF SELFMODIFY {
BIT LCRWEN+LCBNK2
BIT LCRWEN+LCBNK2
}
JMP FETCHOP
IINTRPX PLA
STA TMPL
@ -243,6 +252,10 @@ IINTRPX PLA
STA OPPAGE
SEI
STA ALTRDON
!IF SELFMODIFY {
BIT LCRWEN+LCBNK2
BIT LCRWEN+LCBNK2
}
JMP FETCHOP
;************************************************************
;* *
@ -391,7 +404,7 @@ OPXTBL !WORD ZERO,ADD,SUB,MUL,DIV,MOD,INCR,DECR ; 00 02 04 06 08 0A 0C 0E
!WORD LNOT,LOR,LAND,LA,LLA,CB,CW,CSX ; 20 22 24 26 28 2A 2C 2E
!WORD DROP,DUP,PUSHEP,PULLEP,BRGT,BRLT,BREQ,BRNE ; 30 32 34 36 38 3A 3C 3E
!WORD ISEQ,ISNE,ISGT,ISLT,ISGE,ISLE,BRFLS,BRTRU ; 40 42 44 46 48 4A 4C 4E
!WORD BRNCH,IBRNCH,CALLX,ICALX,ENTER,LEAVEX,RETX,NEXTOP; 50 52 54 56 58 5A 5C 5E
!WORD BRNCH,IBRNCH,CALLX,ICALX,ENTER,LEAVEX,RETX,CFFB; 50 52 54 56 58 5A 5C 5E
!WORD LBX,LWX,LLBX,LLWX,LABX,LAWX,DLB,DLW ; 60 62 64 66 68 6A 6C 6E
!WORD SB,SW,SLB,SLW,SAB,SAW,DAB,DAW ; 70 72 74 76 78 7A 7C 7E
;*
@ -844,6 +857,17 @@ _CEXSX LDA (IP),Y ; SKIP TO NEXT OP ADDR AFTER STRING
;*
;* LOAD VALUE FROM ADDRESS TAG
;*
!IF SELFMODIFY {
LB LDA ESTKL,X
STA LBLDA+1
LDA ESTKH,X
STA LBLDA+2
LBLDA LDA $FFFF
STA ESTKL,X
LDA #$00
STA ESTKH,X
JMP NEXTOP
} ELSE {
LB LDA ESTKL,X
STA TMPL
LDA ESTKH,X
@ -855,6 +879,7 @@ LB LDA ESTKL,X
STY ESTKH,X
LDY IPY
JMP NEXTOP
}
LW LDA ESTKL,X
STA TMPL
LDA ESTKH,X
@ -869,6 +894,19 @@ LW LDA ESTKL,X
LDY IPY
JMP NEXTOP
;
!IF SELFMODIFY {
LBX LDA ESTKL,X
STA LBXLDA+1
LDA ESTKH,X
STA LBXLDA+2
STA ALTRDOFF
LBXLDA LDA $FFFF
STA ESTKL,X
LDA #$00
STA ESTKH,X
STA ALTRDON
JMP NEXTOP
} ELSE {
LBX LDA ESTKL,X
STA TMPL
LDA ESTKH,X
@ -882,6 +920,7 @@ LBX LDA ESTKL,X
LDY IPY
STA ALTRDON
JMP NEXTOP
}
LWX LDA ESTKL,X
STA TMPL
LDA ESTKH,X
@ -967,6 +1006,20 @@ LLWX +INC_IP
;*
;* LOAD VALUE FROM ABSOLUTE ADDRESS
;*
!IF SELFMODIFY {
LAB +INC_IP
LDA (IP),Y
STA LABLDA+1
+INC_IP
LDA (IP),Y
STA LABLDA+2
LABLDA LDA $FFFF
DEX
STA ESTKL,X
LDA #$00
STA ESTKH,X
JMP NEXTOP
} ELSE {
LAB +INC_IP
LDA (IP),Y
STA TMPL
@ -981,6 +1034,7 @@ LAB +INC_IP
STY ESTKH,X
LDY IPY
JMP NEXTOP
}
LAW +INC_IP
LDA (IP),Y
STA TMPL
@ -998,6 +1052,22 @@ LAW +INC_IP
LDY IPY
JMP NEXTOP
;
!IF SELFMODIFY {
LABX +INC_IP
LDA (IP),Y
STA LABXLDA+1
+INC_IP
LDA (IP),Y
STA LABXLDA+2
STA ALTRDOFF
LABXLDA LDA $FFFF
DEX
STA ESTKL,X
LDA #$00
STA ESTKH,X
STA ALTRDON
JMP NEXTOP
} ELSE {
LABX +INC_IP
LDA (IP),Y
STA TMPL
@ -1014,6 +1084,7 @@ LABX +INC_IP
STA ALTRDON
LDY IPY
JMP NEXTOP
}
LAWX +INC_IP
LDA (IP),Y
STA TMPL
@ -1035,6 +1106,18 @@ LAWX +INC_IP
;*
;* STORE VALUE TO ADDRESS
;*
!IF SELFMODIFY {
SB LDA ESTKL,X
STA SBSTA+1
LDA ESTKH,X
STA SBSTA+2
LDA ESTKL+1,X
SBSTA STA $FFFF
INX
; INX
; JMP NEXTOP
JMP DROP
} ELSE {
SB LDA ESTKL,X
STA TMPL
LDA ESTKH,X
@ -1048,6 +1131,7 @@ SB LDA ESTKL,X
; INX
; JMP NEXTOP
JMP DROP
}
SW LDA ESTKL,X
STA TMPL
LDA ESTKH,X
@ -1115,6 +1199,19 @@ DLW +INC_IP
;*
;* STORE VALUE TO ABSOLUTE ADDRESS
;*
!IF SELFMODIFY {
SAB +INC_IP
LDA (IP),Y
STA SABSTA+1
+INC_IP
LDA (IP),Y
STA SABSTA+2
LDA ESTKL,X
SABSTA STA $FFFF
; INX
; JMP NEXTOP
JMP DROP
} ELSE {
SAB +INC_IP
LDA (IP),Y
STA TMPL
@ -1129,6 +1226,7 @@ SAB +INC_IP
; INX
; JMP NEXTOP
JMP DROP
}
SAW +INC_IP
LDA (IP),Y
STA TMPL
@ -1149,6 +1247,17 @@ SAW +INC_IP
;*
;* STORE VALUE TO ABSOLUTE ADDRESS WITHOUT POPPING STACK
;*
!IF SELFMODIFY {
DAB +INC_IP
LDA (IP),Y
STA DABSTA+1
+INC_IP
LDA (IP),Y
STA DABSTA+2
LDA ESTKL,X
DABSTA STA $FFFF
JMP NEXTOP
} ELSE {
DAB +INC_IP
LDA (IP),Y
STA TMPL
@ -1161,6 +1270,7 @@ DAB +INC_IP
STA (TMP),Y
LDY IPY
JMP NEXTOP
}
DAW +INC_IP
LDA (IP),Y
STA TMPL
@ -1334,6 +1444,10 @@ CALL +INC_IP
STA IPH
LDA #>OPTBL ; MAKE SURE WE'RE INDEXING THE RIGHT TABLE
STA OPPAGE
!IF SELFMODIFY {
BIT LCRWEN+LCBNK2
BIT LCRWEN+LCBNK2
}
JMP NEXTOP
;
CALLX +INC_IP
@ -1361,6 +1475,10 @@ CALLX +INC_IP
STA IPH
LDA #>OPXTBL ; MAKE SURE WE'RE INDEXING THE RIGHT TABLE
STA OPPAGE
!IF SELFMODIFY {
BIT LCRWEN+LCBNK2
BIT LCRWEN+LCBNK2
}
JMP NEXTOP
;*
;* INDIRECT CALL TO ADDRESS (NATIVE CODE)
@ -1385,6 +1503,10 @@ ICAL LDA ESTKL,X
STA IPH
LDA #>OPTBL ; MAKE SURE WE'RE INDEXING THE RIGHT TABLE
STA OPPAGE
!IF SELFMODIFY {
BIT LCRWEN+LCBNK2
BIT LCRWEN+LCBNK2
}
JMP NEXTOP
;
ICALX LDA ESTKL,X
@ -1411,6 +1533,10 @@ ICALX LDA ESTKL,X
STA IPH
LDA #>OPXTBL ; MAKE SURE WE'RE INDEXING THE RIGHT TABLE
STA OPPAGE
!IF SELFMODIFY {
BIT LCRWEN+LCBNK2
BIT LCRWEN+LCBNK2
}
JMP NEXTOP
;*
;* JUMP INDIRECT TRHOUGH TMP

View File

@ -5,6 +5,7 @@
;* SYSTEM ROUTINES AND LOCATIONS
;*
;**********************************************************
SELFMODIFY = 1
;
; HARDWARE REGISTERS
;
@ -598,6 +599,17 @@ _CEXS LDA (IP),Y ; SKIP TO NEXT OP ADDR AFTER STRING
;*
;* LOAD VALUE FROM ADDRESS TAG
;*
!IF SELFMODIFY {
LB LDA ESTKL,X
STA LBLDA+1
LDA ESTKH,X
STA LBLDA+2
LBLDA LDA $FFFF
STA ESTKL,X
LDA #$00
STA ESTKH,X
JMP NEXTOP
} ELSE {
LB LDA ESTKL,X
STA TMPL
LDA ESTKH,X
@ -609,6 +621,7 @@ LB LDA ESTKL,X
STY ESTKH,X
LDY IPY
JMP NEXTOP
}
LW LDA ESTKL,X
STA TMPL
LDA ESTKH,X
@ -664,6 +677,20 @@ LLW +INC_IP
;*
;* LOAD VALUE FROM ABSOLUTE ADDRESS
;*
!IF SELFMODIFY {
LAB +INC_IP
LDA (IP),Y
STA LABLDA+1
+INC_IP
LDA (IP),Y
STA LABLDA+2
LABLDA LDA $FFFF
DEX
STA ESTKL,X
LDA #$00
STA ESTKH,X
JMP NEXTOP
} ELSE {
LAB +INC_IP
LDA (IP),Y
STA TMPL
@ -678,6 +705,7 @@ LAB +INC_IP
STY ESTKH,X
LDY IPY
JMP NEXTOP
}
LAW +INC_IP
LDA (IP),Y
STA TMPL
@ -697,6 +725,18 @@ LAW +INC_IP
;*
;* STORE VALUE TO ADDRESS
;*
!IF SELFMODIFY {
SB LDA ESTKL,X
STA SBSTA+1
LDA ESTKH,X
STA SBSTA+2
LDA ESTKL+1,X
SBSTA STA $FFFF
INX
; INX
; JMP NEXTOP
JMP DROP
} ELSE {
SB LDA ESTKL,X
STA TMPL
LDA ESTKH,X
@ -710,6 +750,7 @@ SB LDA ESTKL,X
; INX
; JMP NEXTOP
JMP DROP
}
SW LDA ESTKL,X
STA TMPL
LDA ESTKH,X
@ -777,6 +818,19 @@ DLW +INC_IP
;*
;* STORE VALUE TO ABSOLUTE ADDRESS
;*
!IF SELFMODIFY {
SAB +INC_IP
LDA (IP),Y
STA SABSTA+1
+INC_IP
LDA (IP),Y
STA SABSTA+2
LDA ESTKL,X
SABSTA STA $FFFF
; INX
; JMP NEXTOP
JMP DROP
} ELSE {
SAB +INC_IP
LDA (IP),Y
STA TMPL
@ -791,6 +845,7 @@ SAB +INC_IP
; INX
; JMP NEXTOP
JMP DROP
}
SAW +INC_IP
LDA (IP),Y
STA TMPL
@ -811,6 +866,17 @@ SAW +INC_IP
;*
;* STORE VALUE TO ABSOLUTE ADDRESS WITHOUT POPPING STACK
;*
!IF SELFMODIFY {
DAB +INC_IP
LDA (IP),Y
STA DABSTA+1
+INC_IP
LDA (IP),Y
STA DABSTA+2
LDA ESTKL,X
DABSTA STA $FFFF
JMP NEXTOP
} ELSE {
DAB +INC_IP
LDA (IP),Y
STA TMPL
@ -823,6 +889,7 @@ DAB +INC_IP
STA (TMP),Y
LDY IPY
JMP NEXTOP
}
DAW +INC_IP
LDA (IP),Y
STA TMPL

View File

@ -1,41 +1,41 @@
;**********************************************************
;*
;* VM ZERO PAGE LOCATIONS
;* VM ZERO PAGE LOCATIONS
;*
;**********************************************************
SRC = $06
SRCL = SRC
SRCH = SRC+1
DST = SRC+2
DSTL = DST
DSTH = DST+1
ESTKSZ = $20
XSTK = $A0
XSTKL = XSTK
XSTKH = XSTK+ESTKSZ/2
ESTK = $C0
ESTKL = ESTK
ESTKH = ESTK+ESTKSZ/2
VMZP = ESTK+ESTKSZ
ESP = VMZP
DVSIGN = VMZP
IFP = ESP+1
IFPL = IFP
IFPH = IFP+1
SRC = $06
SRCL = SRC
SRCH = SRC+1
DST = SRC+2
DSTL = DST
DSTH = DST+1
ESTKSZ = $20
XSTK = $A0
XSTKL = XSTK
XSTKH = XSTK+ESTKSZ/2
ESTK = $C0
ESTKL = ESTK
ESTKH = ESTK+ESTKSZ/2
VMZP = ESTK+ESTKSZ
ESP = VMZP
DVSIGN = VMZP
IFP = ESP+1
IFPL = IFP
IFPH = IFP+1
PP = IFP+2
PPL = PP
PPH = PP+1
IPY = PP+2
TMP = IPY+1
TMPL = TMP
TMPH = TMP+1
NPARMS = TMPL
FRMSZ = TMPH
DROP = $EF
NEXTOP = $F0
PPL = PP
PPH = PP+1
IPY = PP+2
TMP = IPY+1
TMPL = TMP
TMPH = TMP+1
NPARMS = TMPL
FRMSZ = TMPH
DROP = $EF
NEXTOP = $F0
FETCHOP = NEXTOP+3
IP = FETCHOP+1
IPL = IP
IPH = IPL+1
OPIDX = FETCHOP+6
OPPAGE = OPIDX+1
IP = FETCHOP+1
IPL = IP
IPH = IPL+1
OPIDX = FETCHOP+6
OPPAGE = OPIDX+1