Pascal-S
Forum rules
This is the only download category to upload works in progress of your application or game.
This is the only download category to upload works in progress of your application or game.
Re: Pascal-S
More changes!
I had forgotten, until yesterday, that I had a task left unfulfilled, which was allowing more than just single digit integers to be 'read' into arrays. This is now possible, see the automata example program for usage. I have not yet added the capability to mix in non-printable characters into 'string' arrays yet.
I also decided to revisit the comment issue and have finally managed to get them working. See again the automata example program or simply start adding comments, inside curly brackets, only at the end of lines.
In the .zip file, I have reworked the readme file and added a brief manual section. For general Pascal information, I recommend referring to online sources or books if you have them, but I point out the 'idiosynchrosies' of Pascal-iSh, in order to hopefully help anyone having difficulties. There are also some clues as to the upcoming 'improvements'.
The .zip file in post one has been updated.
I had forgotten, until yesterday, that I had a task left unfulfilled, which was allowing more than just single digit integers to be 'read' into arrays. This is now possible, see the automata example program for usage. I have not yet added the capability to mix in non-printable characters into 'string' arrays yet.
I also decided to revisit the comment issue and have finally managed to get them working. See again the automata example program or simply start adding comments, inside curly brackets, only at the end of lines.
In the .zip file, I have reworked the readme file and added a brief manual section. For general Pascal information, I recommend referring to online sources or books if you have them, but I point out the 'idiosynchrosies' of Pascal-iSh, in order to hopefully help anyone having difficulties. There are also some clues as to the upcoming 'improvements'.
The .zip file in post one has been updated.
Re: Pascal-S
New version.
Changes:
1) I have removed the 'CLEAR' standard function in an attempt to conserve 'identifier' space. Use this method instead:
CH:=CHR(147);
WRITE(CH);
This is similar to BASIC, where you would just do PRINT CHR$(147) to clear the text screen. I made the discovery that you cannot use a procedure or a function as a parameter to another procedure or function. Consequently, as shown above, you need to get the result of the function then use that result in the following function or procedure.
2) I made another attempt at fixing the use of '&' for doing bitwise ands. This was one of my first attempts at expanding Pascal-iSh, way back when. At first it appeared to work as desired, but then I started to see problems. I was not successful in fixing it and I can't figure out why, so, I punted. I have made a new standard function...BITAND(n1,n2). It's not what I wanted, but I want to be able to do bitwise 'ands' and probably 'ors' too. As a consequence, I have increased the maximum number of 'identifiers' up to 185. I'm doing this in steps, since I need to leave some headroom below $8000, since that's where the interpreter gets loaded to. I could exceed this and then remove the ability to run the interpreter from the compiler....I'll cross that bridge if I need to. A caution when using BITAND(), for some reason, if used inside a loop, it causes issues, I don't know why? So, don't use it inside loops. This wastes p-code space, but until I can figure out something better, it will have to do. See the Automata app for usage.
3) Another new standard function is VPOKE(). I don't even try to pass parameters inside the function, use it thus:
PROCEDURE VPUT(BANK,ADDR,VAL: INTEGER);
BEGIN
REGS[AR]:=BANK;
REGS[0]:=ADDR;
REGS[YR]:=VAL;
VPOKE();
END;
There will be a VPEEK when I need to make use of it, or sooner if someone requests it.
4) Also, SIN() & COS() functions are available now. These both require an argument of an angle (in degrees) and will return the result*255, ie. SIN(20) will return 87, which, when multiplied by the desired value, must be divided by 255 to get the approximate result. This is a compromise, due to the fact that Pascal-iSh has only integers and it gives reasonable results. See the SINE.PAS program.
There seems to be a never ending list of 'improvements' or additions, that I'd like to make to Pascal-iSh. After getting the bell sound working, which is pretty pedestrian, I started to think about the 'newer' additions to BASIC. There are too many commands to implement, but I have started to think about adding one or two, to give Pascal-iSh a better 'voice'. I had hoped that I could use CALL to do this from Pascal itself, but the BASIC sound code is in another ROM bank and will require adding new standard functions to access.
The .zip in post #1 has been updated, with two new demo programs, sine.pas and balls.pas, also a new version of the automata program (automatas.pas).
Changes:
1) I have removed the 'CLEAR' standard function in an attempt to conserve 'identifier' space. Use this method instead:
CH:=CHR(147);
WRITE(CH);
This is similar to BASIC, where you would just do PRINT CHR$(147) to clear the text screen. I made the discovery that you cannot use a procedure or a function as a parameter to another procedure or function. Consequently, as shown above, you need to get the result of the function then use that result in the following function or procedure.
2) I made another attempt at fixing the use of '&' for doing bitwise ands. This was one of my first attempts at expanding Pascal-iSh, way back when. At first it appeared to work as desired, but then I started to see problems. I was not successful in fixing it and I can't figure out why, so, I punted. I have made a new standard function...BITAND(n1,n2). It's not what I wanted, but I want to be able to do bitwise 'ands' and probably 'ors' too. As a consequence, I have increased the maximum number of 'identifiers' up to 185. I'm doing this in steps, since I need to leave some headroom below $8000, since that's where the interpreter gets loaded to. I could exceed this and then remove the ability to run the interpreter from the compiler....I'll cross that bridge if I need to. A caution when using BITAND(), for some reason, if used inside a loop, it causes issues, I don't know why? So, don't use it inside loops. This wastes p-code space, but until I can figure out something better, it will have to do. See the Automata app for usage.
3) Another new standard function is VPOKE(). I don't even try to pass parameters inside the function, use it thus:
PROCEDURE VPUT(BANK,ADDR,VAL: INTEGER);
BEGIN
REGS[AR]:=BANK;
REGS[0]:=ADDR;
REGS[YR]:=VAL;
VPOKE();
END;
There will be a VPEEK when I need to make use of it, or sooner if someone requests it.
4) Also, SIN() & COS() functions are available now. These both require an argument of an angle (in degrees) and will return the result*255, ie. SIN(20) will return 87, which, when multiplied by the desired value, must be divided by 255 to get the approximate result. This is a compromise, due to the fact that Pascal-iSh has only integers and it gives reasonable results. See the SINE.PAS program.
There seems to be a never ending list of 'improvements' or additions, that I'd like to make to Pascal-iSh. After getting the bell sound working, which is pretty pedestrian, I started to think about the 'newer' additions to BASIC. There are too many commands to implement, but I have started to think about adding one or two, to give Pascal-iSh a better 'voice'. I had hoped that I could use CALL to do this from Pascal itself, but the BASIC sound code is in another ROM bank and will require adding new standard functions to access.
The .zip in post #1 has been updated, with two new demo programs, sine.pas and balls.pas, also a new version of the automata program (automatas.pas).
Re: Pascal-S
A question for anyone using this, or anyone that cares to comment. Currently, Pascal-iSh has a limit to program code size of 4096 p-codes. This is includes p-code as well as data that is contained within the Pascal-iSh source code, such as strings or any initialized array. I've increased this maximum in steps, from the original limit of 2000 in the original source code. The current limit is predicated on the fact that by design, each p-code has the potential to be associated with a corresponding word of data, not all of this data is used with any given p-code, but is there nonetheless. So, 4096 p-code requires 8192 bytes of data, which is 1 bank of high ram. To go beyond 4096, is to require an additional bank of high ram. This is not a difficult thing to do, but doing it comes at a cost in program execution speed, since now the interpreter must check the value of the program counter at the start of the p-code interpreter loop so as to know which bank to switch into the low ram 'window'. Until just recently, I have not come very close to exceeding the 4096 limit, but obviously, a program with a large amount of initialized data, has this potential. Coding the interpreter to do this check shows about a 5% speed hit. Pascal-iSh is already slow. As this is already a moot point, since this project is more of a personal 'voyage' than anything really useful, it probably doesn't matter. Still, as an exercise, in the imaginary world that this would actually be used by anyone, does it make sense to implement an increase in the p-code maximum to 8192? This would be the last increase, as to go beyond would be even more expensive from an execution speed perspective and I doubt that anyone would ever code such a massive program in Pascal-iSh! Additionally, I think that if(when) I add file read/write capabilities, it would reduce the 'footprint' of programs with large data sets, where an array could be initialized from a file with a read loop, rather than being encoded within the source, which is somewhat expensive in terms of p-code required. This would perhaps stave off the need to increase to 8192....this is perhaps an incorrect assumption, since I'm not sure of the 'overhead' that file usage will require...
- ahenry3068
- Posts: 1136
- Joined: Tue Apr 04, 2023 9:57 pm
Re: Pascal-S
The interpreter is written in BASIC, correct ? 5% isn't that great, bank switching isn't near that expensive at the hardware level so that hit is probably mostly BASIC overhead. Go ahead and implement the 8196 increase and send me the source for the interpreter. Flag the part that does the Bank check prominently with REMARKS in the source. Tell me what string to search in the editor for that section. I'll see if I can do up an ML sub for that section that mitigates that 5% hit by some amount. I'll include the ML back in the source as Data and write a sub to POKE it for you. Is your program currently using any of the Golden Ram area ($400-$7FF) ? ? That's where the ML code will live in memory.yock1960 wrote: ↑Fri Apr 05, 2024 11:17 am A question for anyone using this, or anyone that cares to comment. Currently, Pascal-iSh has a limit to program code size of 4096 p-codes. This is includes p-code as well as data that is contained within the Pascal-iSh source code, such as strings or any initialized array. I've increased this maximum in steps, from the original limit of 2000 in the original source code. The current limit is predicated on the fact that by design, each p-code has the potential to be associated with a corresponding word of data, not all of this data is used with any given p-code, but is there nonetheless. So, 4096 p-code requires 8192 bytes of data, which is 1 bank of high ram. To go beyond 4096, is to require an additional bank of high ram. This is not a difficult thing to do, but doing it comes at a cost in program execution speed, since now the interpreter must check the value of the program counter at the start of the p-code interpreter loop so as to know which bank to switch into the low ram 'window'. Until just recently, I have not come very close to exceeding the 4096 limit, but obviously, a program with a large amount of initialized data, has this potential. Coding the interpreter to do this check shows about a 5% speed hit. Pascal-iSh is already slow. As this is already a moot point, since this project is more of a personal 'voyage' than anything really useful, it probably doesn't matter. Still, as an exercise, in the imaginary world that this would actually be used by anyone, does it make sense to implement an increase in the p-code maximum to 8192? This would be the last increase, as to go beyond would be even more expensive from an execution speed perspective and I doubt that anyone would ever code such a massive program in Pascal-iSh! Additionally, I think that if(when) I add file read/write capabilities, it would reduce the 'footprint' of programs with large data sets, where an array could be initialized from a file with a read loop, rather than being encoded within the source, which is somewhat expensive in terms of p-code required. This would perhaps stave off the need to increase to 8192....this is perhaps an incorrect assumption, since I'm not sure of the 'overhead' that file usage will require...
Re: Pascal-S
No, all code is either Prog8 or assembly. I did a small assembly snippet for the check, to use the correct bank for the first or second bank of data, it helped some, putting the speed 'hit' from just over 5% to just under versus the straight Prog8 code.. Prog8 is pretty good, but I guess all compilers have a bit of overhead, since they can't make assumptions in all cases.ahenry3068 wrote: ↑Fri Apr 05, 2024 11:25 am
The interpreter is written in BASIC, correct ? 5% isn't that great, bank switching isn't near that expensive at the hardware level so that hit is probably mostly BASIC overhead. Go ahead and implement the 8196 increase and send me the source for the interpreter. Flag the part that does the Bank check prominently with REMARKS in the source. Tell me what string to search in the editor for that section. I'll see if I can do up an ML sub for that section that mitigates that 5% hit by some amount. I'll include the ML back in the source as Data and write a sub to POKE it for you. Is your program currently using any of the Golden Ram area ($400-$7FF) ? ? That's where the ML code will live in memory.
I had a thought yesterday, about somehow incorporating some method to implement a type of 'memory model' system into the 'works', where you could basically 'have your cake and it eat, too', have the 'speed' for smaller projects, but the ability to have bigger projects, that will necessarily be slower. I would like to do this without having a bunch of different executables, or somehow 'shielding' users from such messiness...but haven't thought on that enough yet.
Re: Pascal-S
Speaking of 'speed', I've been adding machine code to more of the demo programs. No inline assembly code, not sure I will ever implement such capability, but I have written a helper program to take the drudgery and mistake potential, away from converting machine code bytes into signed integers for incorporation into Pascal-iSh source. A 58 byte routine reduced plot time for the automata demo from 83 seconds or so, to 45! I'm getting close to posting a major update here... hopefully in the next few days.
- ahenry3068
- Posts: 1136
- Joined: Tue Apr 04, 2023 9:57 pm
Re: Pascal-S
I was in a back and forth on asm-dev(Discord) a couple days ago with treeman0013. We came up with the following routine to allow Calling ROM routines from "Cartridge code" which is itself in ROM. This routine is first copied down to $0400. To make the BIOS call the Cartridge code sets up for it as usual (Registers and Parameters) Then stores the desired ROM call address in r14 and does a JSR $400yock1960 wrote: ↑Sun Apr 07, 2024 8:04 amNo, all code is either Prog8 or assembly. I did a small assembly snippet for the check, to use the correct bank for the first or second bank of data, it helped some, putting the speed 'hit' from just over 5% to just under versus the straight Prog8 code.. Prog8 is pretty good, but I guess all compilers have a bit of overhead, since they can't make assumptions in all cases.ahenry3068 wrote: ↑Fri Apr 05, 2024 11:25 am
The interpreter is written in BASIC, correct ? 5% isn't that great, bank switching isn't near that expensive at the hardware level so that hit is probably mostly BASIC overhead. Go ahead and implement the 8196 increase and send me the source for the interpreter. Flag the part that does the Bank check prominently with REMARKS in the source. Tell me what string to search in the editor for that section. I'll see if I can do up an ML sub for that section that mitigates that 5% hit by some amount. I'll include the ML back in the source as Data and write a sub to POKE it for you. Is your program currently using any of the Golden Ram area ($400-$7FF) ? ? That's where the ML code will live in memory.
I had a thought yesterday, about somehow incorporating some method to implement a type of 'memory model' system into the 'works', where you could basically 'have your cake and it eat, too', have the 'speed' for smaller projects, but the ability to have bigger projects, that will necessarily be slower. I would like to do this without having a bunch of different executables, or somehow 'shielding' users from such messiness...but haven't thought on that enough yet.
The "Trampoline" saves and switchs ROM banks. Does the BIOS call. Then returns to the Calling ROM code. Kind of like JSRFAR does, except with Cartridge code NONE of the ROM calls are directly available. This uses self modifying code.
The point of posting this is a similar approach can be used for "Procedural Variables" (In this code the "Procedural Variable" is r14).
Turbo Pascal on the PC had this feature and it was extremely useful. 1 example would be having a generic Shell Sort routine where "Compare" & "Swap Value" were procedural variables. That way 1 routine could sort many different Data Types. Just rewrite Compare & "Swap Value".
By using procedural variables you can avoid the use of "if thens" for calling different subroutines for different situations. Instead you've made the procedure itself a "Variable"
Code: Select all
ROM_BANK = 1
trampoline:
phx
ldx ROM_BANK ; THE ROM BANK
stx bank_to_jmp ; VARIABLE ON ZEROPAGE
stz ROM_BANK ; #$01
ldx r14+1
stx OPADDR+1
ldx r14
stx OPADDR
plx
jsr $FFFF
OPADDR = * -2
pha
lda bank_to_jmp
sta ROM_BANK
pla
rts
Re: Pascal-S
That certainly looks useful for 'code' in different 'banks', but, I don't think it would be efficient in this case. The 'interpreter' sits in 'low ram' starting at $8000 and is just a loop that increments the program counter (PC) gets the p-code from the 'code bank' then based on the p-code, runs the code in low ram for that p-code, which it does with a big switch-case (Prog8 'when') construct. A given p-code may or may not need to change banks, since they don't all have an argument or operand, but most do, so there is quite a bit of bank switching going on, over and above that which occurs from the Kernal. After the main loop fetches the p-code, I inserted this:ahenry3068 wrote: ↑Sun Apr 07, 2024 8:38 amI was in a back and forth on asm-dev(Discord) a couple days ago with treeman0013. We came up with the following routine to allow Calling ROM routines from "Cartridge code" which is itself in ROM. This routine is first copied down to $0400. To make the BIOS call the Cartridge code sets up for it as usual (Registers and Parameters) Then stores the desired ROM call address in r14 and does a JSR $400yock1960 wrote: ↑Sun Apr 07, 2024 8:04 amNo, all code is either Prog8 or assembly. I did a small assembly snippet for the check, to use the correct bank for the first or second bank of data, it helped some, putting the speed 'hit' from just over 5% to just under versus the straight Prog8 code.. Prog8 is pretty good, but I guess all compilers have a bit of overhead, since they can't make assumptions in all cases.ahenry3068 wrote: ↑Fri Apr 05, 2024 11:25 am
The interpreter is written in BASIC, correct ? 5% isn't that great, bank switching isn't near that expensive at the hardware level so that hit is probably mostly BASIC overhead. Go ahead and implement the 8196 increase and send me the source for the interpreter. Flag the part that does the Bank check prominently with REMARKS in the source. Tell me what string to search in the editor for that section. I'll see if I can do up an ML sub for that section that mitigates that 5% hit by some amount. I'll include the ML back in the source as Data and write a sub to POKE it for you. Is your program currently using any of the Golden Ram area ($400-$7FF) ? ? That's where the ML code will live in memory.
I had a thought yesterday, about somehow incorporating some method to implement a type of 'memory model' system into the 'works', where you could basically 'have your cake and it eat, too', have the 'speed' for smaller projects, but the ability to have bigger projects, that will necessarily be slower. I would like to do this without having a bunch of different executables, or somehow 'shielding' users from such messiness...but haven't thought on that enough yet.
The "Trampoline" saves and switchs ROM banks. Does the BIOS call. Then returns to the Calling ROM code. Kind of like JSRFAR does, except with Cartridge code NONE of the ROM calls are directly available. This uses self modifying code.
The point of posting this is a similar approach can be used for "Procedural Variables" (In this code the "Procedural Variable" is r14).
Turbo Pascal on the PC had this feature and it was extremely useful. 1 example would be having a generic Shell Sort routine where "Compare" & "Swap Value" were procedural variables. That way 1 routine could sort many different Data Types. Just rewrite Compare & "Swap Value".
By using procedural variables you can avoid the use of "if thens" for calling different subroutines for different situations. Instead you've made the procedure itself a "Variable"
Code: Select all
ROM_BANK = 1 trampoline: phx ldx ROM_BANK ; THE ROM BANK stx bank_to_jmp ; VARIABLE ON ZEROPAGE stz ROM_BANK ; #$01 ldx r14+1 stx OPADDR+1 ldx r14 stx OPADDR plx jsr $FFFF OPADDR = * -2 pha lda bank_to_jmp sta ROM_BANK pla rts
Code: Select all
%asm{{
lda p8v_pc+1 ;get high byte of pc (program counter)
cmp #$10 ;is it $10?
bmi + ;if minus flag set {less than), then pc < $1000, set bank 3
lda p8v_pc ;else need to check low byte
beq + ;if not zero, then pc > $1000, set bank 4
lda #$04 ;bank 4
sta p8v_dbank
bra ++
+ lda #$03 ;bank 3
sta p8v_dbank
+
}}
Perhaps I'm missing something in your given example? I could probably get a little more speed back, by taking this code out from where it is executed every time through the loop, but only for those opcodes that would need it. Maybe I'll play with that later today.
In any case, although I may go through with allowing 8k of p-code in some fashion, I finally got around to writing some Pascal routines to do file access, which allowed me to read in data to fill a 765 element array using a loop, instead of encoding that data inside the Pascal source. This reduced the p-code footprint for that particular program from approx. 4000 p-codes to under 1900 p-codes and that's with the added 'footprint' of the Pascal code for a filename variable, converting that to a 'normal' string....no packed arrays in Pascal-iSh....then the file open procedure, and the loop to do 'chrin' to fill the 765 element array, all of which was about 200 p-codes if my memory serves me well...
- ahenry3068
- Posts: 1136
- Joined: Tue Apr 04, 2023 9:57 pm
Re: Pascal-S
I said a similiar approach. You would probably want to take out all the Banking stuff just to use this to call procedural variables.
There is a bit of overhead to the approach. But you would use it where otherwise there would be a lot of branching to select call path so your eliminating that other overhead.
Again I fall back to Pascal to illustrate the approach, you would have to go about it a bit differently in assembly or Prog8
{procedure declaration} Procedure QuickSort (function Compare(&Data1; &Data2;) : boolean; procedure SwapData(&Data1; &Data2;); &SortData; SizeData : LongInt;);
In that example QuickSort would be able to sort almost ANY Data. The quicksort routine itself would only have calls to Compare & SwapData in the procedure code itself. The functions and procedures to do the sorting and swapping would be passed in as parameters. This is VERY Powerful. In some way's it was kind of the precursor to Object oriented programming. Objects work much the same at the Machine Language level.
There is a bit of overhead to the approach. But you would use it where otherwise there would be a lot of branching to select call path so your eliminating that other overhead.
Again I fall back to Pascal to illustrate the approach, you would have to go about it a bit differently in assembly or Prog8
{procedure declaration} Procedure QuickSort (function Compare(&Data1; &Data2;) : boolean; procedure SwapData(&Data1; &Data2;); &SortData; SizeData : LongInt;);
In that example QuickSort would be able to sort almost ANY Data. The quicksort routine itself would only have calls to Compare & SwapData in the procedure code itself. The functions and procedures to do the sorting and swapping would be passed in as parameters. This is VERY Powerful. In some way's it was kind of the precursor to Object oriented programming. Objects work much the same at the Machine Language level.
Re: Pascal-S
Perhaps too advanced for me...many years ago, when I looked at C++....it was like....this is a "bridge too far"! My brain struggles with too much indirection!ahenry3068 wrote: ↑Sun Apr 07, 2024 11:58 am I said a similiar approach. You would probably want to take out all the Banking stuff just to use this to call procedural variables.
There is a bit of overhead to the approach. But you would use it where otherwise there would be a lot of branching to select call path so your eliminating that other overhead.
Again I fall back to Pascal to illustrate the approach, you would have to go about it a bit differently in assembly or Prog8
{procedure declaration} Procedure QuickSort (function Compare(&Data1; &Data2;) : boolean; procedure SwapData(&Data1; &Data2;); &SortData; SizeData : LongInt;);
In that example QuickSort would be able to sort almost ANY Data. The quicksort routine itself would only have calls to Compare & SwapData in the procedure code itself. The functions and procedures to do the sorting and swapping would be passed in as parameters. This is VERY Powerful. In some way's it was kind of the precursor to Object oriented programming. Objects work much the same at the Machine Language level.
On the plus side, I did play about with taking the check out of the main loop and adding it only for those p-codes that require an operand, only 19 out of the current total of 59 p-codes. Making it a subroutine slowed it down even more, but making it into a macro speeded things back up for a net gain of about 2.5%, so now the speed hit is down from about 5% to 2.5%. That's almost insignificant in my book and more palatable for just not worrying about and not bothering to get really 'fancy' with different memory models.