Jump to content
IGNORED

Developing a new language - ACUSOL


Pab

Recommended Posts

Previous link I posted doesn't redirect to the desired page, so here's the detection routine from SysInfo, written by KMK:

; Bank select RAM detection
; Stolen from the SysInfo
;
; Must NOT be located within the $4000-$7FFF !!!
;
portb	=	$d301
extra	=	$4000
;
	lda portb
	pha
	lda #$00
	sta counter
	ldx #$7f	;Save the ramdisk contents before the test
loop1	txa
	asl
	ora #$01
	sta portb
	lda extra
	sta buffer,x
	dex
	bpl loop1
	ldx #$7f	;Clear tested RAM.
loop2	txa
	asl
	ora #$01
	sta portb
	lda #$00
	sta extra
	dex
	bpl loop2
	lda #$ff	;Reset PORTB
	sta portb
	lda #'K		;Mark base RAM as tested.
	sta extra
	ldx #$7f	;Count banks.
loop3	txa
	asl
	ora #$01
	sta portb
	lda extra
	bne skip
	inc counter
	lda #'K
	sta extra
skip	dex
	bpl loop3
	ldx #$7f	;Restore the ramdisk contents
loop4	txa
	asl
	ora #$01
	sta portb
	lda buffer,x
	sta extra
	dex
	bpl loop4
	pla
	sta portb
	lda counter
	rts
;
counter	.dc	0	;number of banks
buffer	.ds	64	;64-byte buffer
Link to comment
Share on other sites

How obsessive am I about testing this thing?

 

This obsessive.

 

post-12895-0-35896800-1396462725_thumb.gif

 

I can report on the newest bank testing and bank switching code testing under...

 

DOS 2.0S - Passed

DOS 2.5 - Passed

DOS 3 - Passed

DOS XL 2.3 - Passed

DOS 4 - Passed

BWDOS - Passed

MyDOS 4.53 - Passed

SpartaDOS 3.2 - Would not load into banks

SDX 4.46 - Passed

 

Verdict: the language should be able to create programs with code in banked RAM under almost every DOS out there.

 

  • Like 1
Link to comment
Share on other sites

Here is the bank testing code I finally came up with. It takes elements of flashjazzcat's, the Polish routine, and some thoughts of my own.

 

This one avoids the need to shut off interrupts by ignoring bit 0 of PORTB altogether. The value of PORTB on initial call is AND'ed with 1 to isolate that bit, and that setting is OR'ed with the other bits to make sure we don't go swapping the OS in or out at any time.

 

Banks are loaded with test values forwards and checked in reverse, so the highest-valued banks end up at the beginning of the bank table. This guarantees that Bank #1 as referenced by the language is always a stock 130XE's zero bank for maximum compatibility. I intend on testing for SpartaDOS X later on and using their banking table to avoid conflicts. Then the original values are restored.

 

The routine skips FF/FE as a bank possibility because that will always reference the main bank.

10       *=  $0480
20 PORTB =   $D301
30 NUMBANKS = $C9      ;Number of available banks 
40 OLDPORTB = $CA      ;Old value of PORTB
50 SAVEMEM = $8E00
60 BANKMEM = $4000
70 BANKTABLE = $EEEE   ;Replaced on compile
80 SCRATCH = $D4
90       LDA PORTB
0100     STA OLDPORTB  ;Save old value
0110     AND #1
0120     STA SCRATCH   ;Save current OSRAM flag
0130     LDX #0        ;Test banks in forward order
0140 LP1 TXA 
0150     ASL A         
0160     ORA SCRATCH   ;Ignore OSRAM bit.
0170     STA PORTB
0180     LDA $4000
0190     STA SAVEMEM,X ;Save current memory
0200     LDA $4001
0210     STA SAVEMEM+$0100,X
0220     TXA 
0230     STA $4000     ;Save bank number
0240     EOR #$FF
0250     STA $4001     ;And one's compliment for test.
0260     INX 
0270     CPX #$80      ;Only need to test 128 values
0280     BMI LP1
0290     LDX #$7E      ;Test backwards to put highest banks
0300     LDY #0        ;in lowest elements in bank table
0310 LP2 TXA           ;and skip the main bank (FF)
0320     ASL A
0330     ORA SCRATCH
0340     STA PORTB
0350     TXA 
0360     CMP $4000
0370     BNE NOPE      ;Not a unique bank.
0380     EOR #$FF
0390     CMP $4001
0400     BNE NOPE
0410     LDA PORTB 
0430     STA BANKTABLE,Y
0440     INY 
0450 NOPE DEX 
0460     BPL LP2
0465     STY NUMBANKS
0470     LDX #$7F
0480 LP3 TXA 
0490     ASL A
0500     ORA SCRATCH
0510     STA PORTB
0520     LDA SAVEMEM,X
0530     STA $4000
0540     LDA SAVEMEM+$100,X
0550     STA $4001
0560     DEX 
0570     BPL LP3
0580     LDA OLDPORTB
0590     STA PORTB
0600     RTS 
Link to comment
Share on other sites

The banking table is located among the program's global variables. If variables are allocated within the code, it will be 9 bytes into the runtime. If variables are allocated elsewhere (through the VARIABLES option in a MODULE statement) then it will be located in that spot.

 

Since the use of banking already required that the first and last modules and their variables not be located in banked RAM, this doesn't cause much of an added restriction.

 

Allocating the bank table with the variables will make it possible to write and compile code for cartridges with the language that will be able to access banked RAM. A compiler switch will be included for those who want to make cartridges to put the testing code into the main portion of the program instead of loaded from disk and INIT'ed.

Link to comment
Share on other sites

How obsessive am I about testing this thing?

 

This obsessive.

 

attachicon.gifdos3-a.gif

 

I can report on the newest bank testing and bank switching code testing under...

 

DOS 2.0S - Passed

DOS 2.5 - Passed

DOS 3 - Passed

DOS XL 2.3 - Passed

DOS 4 - Passed

BWDOS - Passed

MyDOS 4.53 - Passed

SpartaDOS 3.2 - Would not load into banks

SDX 4.46 - Passed

 

Verdict: the language should be able to create programs with code in banked RAM under almost every DOS out there.

 

Nice - I am surprised I immediately recognized the DOS 3 menu :)

Link to comment
Share on other sites

Dos 3 does work...if you tell Altirra to emulate an 800XL. If you try it as a 130XE, it dumps you to the self-test instead of loading DOS.

 

I think the problem with Sparta is that it seems to be resetting PORTB after loading a segment, and since my tactic to load directly into a bank is to use an INIT segment to switch banks, then let DOS load into the newly swapped bank, it all ends up going into main RAM. Then when the time comes to run each procedure, BRK-boom. Probably has something to do with the way SD 3.2 used OSRAM buffers, and improper masking of PORTB.

Link to comment
Share on other sites

I stepped through it in Altirra to discover exactly what was happening. The previous problems were under 3.2d. For a laugh, I thought I'd try it under 3.2f, and these screencaps are from running under that version.

 

This is after a warm reset, showing the contents of the main bank of RAM after attempting to run the program.

 

post-12895-0-30770600-1396479636_thumb.gif

 

The program then runs the bank detection routine, which correctly identifies all banks in the system.

 

The rest of the runtime (such as it is) loads and takes up residence successfully in main RAM. Then the INIT routine switches to bank EF, "bank 1" in its table.

 

post-12895-0-19207400-1396479742_thumb.gif

 

After the INIT routine finishes, Sparta goes back into its binary load sequence. The instruction at $076C is the culprit.

 

post-12895-0-86635200-1396479830_thumb.gif

 

Which leaves what should be the pristine bank EF as main RAM, which has been written and overwritten by routines.

 

post-12895-0-88668800-1396479879_thumb.gif

 

So we cannot binary load directly into banked RAM under SpartaDOS 3.2 (or, I would imagine, 2.x) since they don't bother to mask the current values. I guess they never figured that anyone would want to binary load anywhere but main RAM.

 

So now the question is, do I go back to load-and-move (with more modules and thus more of a slowdown in loading) or do we just say that programs written in whatever-it's-called that use banking for procedures can't be used under SpartaDOS versions before 4.4x?

Edited by Pab
Link to comment
Share on other sites

Well, that's a turn up for the books. Perhaps Gustafson had a few off-days after all. :) I must have too, since I managed to run my test program with versions of Sparta which didn't exhibit this design flaw (although we shouldn't call it a flaw, since as already said, if direct binary loading into extended banks isn't specified as part of the API, then it's entirely reasonable for the DOS developer not to support it).

 

I'd go for load and move if things are indeed as they appear, and I won't reiterate the numerous reasons for doing so, since I've already explained them all. Slow-downs owing to additional segments and memory moves are completely negligible - again, as already explained. Treat extended banks as you would shadow RAM and the application should be bullet-proof.

 

BTW: Am unable to replicate any problems running DOS 3.0 in Altirra with system set to 65/130XE, 128KB RAM.

Edited by flashjazzcat
Link to comment
Share on other sites

Well, let's call it an oversight, not a flaw.

 

Thanks to flash's SDX bank test, I've got the bank code for the language working in all configurations possible under Altirra for the XL's and XE's. It doesn't want to work with the expansion schemes for the 800 and 1200XL but I'm not surprised by that. (I would have been more surprised had it worked.)

 

I have one interesting bug to report on, though...but not for my code. DOSKEY for SpartaDOS 4.46 allocates a bank for its command line history, but uses the wrong bank for the purpose! The second bank reported by SDX as being available is actually the one DOSKEY is storing its history in, and writing to it trashes the history.

 

I got an E-mail from my editor that my edits will be arriving late tonight or early tomorrow which is going to severely restrict my free time for the next month or so, so this project will be slowing down a little bit. However, I do hope to have arrays and pointers (the next hurdles) ready by the end of the month, which will leave just objects, floating point, and 32 bit math to tackle before the bootstrap compiler is for most intents and purposes finished.

Link to comment
Share on other sites

Okay, it looks like the bank loading code is now functional and ready to lock down.

 

Methodology decided upon was this: when code is to be loaded into a bank, it is actually loaded into the main bank at the current location of the program counter (after whatever the last routine written or variable allocated, whichever is higher), then a 32-byte relocating program is run from $480 which moves the memory into the banks.

 

If the program counter is in the banking window ($4000-$7FFF) then the code is actually loaded into $8000 and moved from there.

 

Code compiled with this strategy now works under all DOS's tested, including SpartaDOS 3.2.

 

Under all DOS's except SpartaDOS X, a bank testing routine will identify all banks of extended RAM and build an array of those available to be used by the bank switching routines. Under SDX, it will query the DOS to find out which banks are free and only use those.

 

The number of banks available will be stored in memory location $C9, and the actual PORTB value for each bank is irrelevant to the programmer. The language's bank switcher will translate a one-byte value from 1-x into the appropriate PORTB value.

Link to comment
Share on other sites

Since I've started mentioning memory locations used, I might as well post a memory map of Page Zero locations used by the language at this point.

 

$A0 ARGTABLE Arguments passed to procedures and functions. Through $AF

$C9 NUMBANKS Number of banks available for programs to work with

$CA OLDPORTB PORTB value for the main bank of RAM

$CB OP1 Two-byte value (lo in CB high in CC) of first operand in math or move operation

$CD OP2 Two-byte value (lo in CD high in CE) of second operand in math or move operation

$CF BANK1 Bank to switch to, or banked location of first operand.

$D1 BANK2 Banked location of second operand

$D4 RES Result of mathematical operation. 16 bits.

 

$D4-$DA are also used periodically for scratch memory, and should not be used by programs.

 

Locations $80 through $9F and $B0 through $C8 are currently unused by the language, and are available for user written programs.

 

$CB through $C1 are generally used internally, but will be documented for inline machine language routines that want to take advantage of the math microruntime package.

Link to comment
Share on other sites

ARGUMENTS TO PROCEDURES AND FUNCTIONS

 

Values passed through arguments are stashed in locations $A0 through $AF. These are then copied into the local variables specified in the procedure definition. If the routine should not store the values locally (for example, inline code that can read $A0-$AF directly) then the compiler switch DEFINE NOARGS can be used.

 

If the procedure or function is a method of an object, the first argument pushed will be a three-byte pointer to the instance of the object that should be worked with.

 

For function calls, the first (or second, if the function is an object method) argument pushed will be a three-byte pointer to the return variable. If there is no return variable (meaning that the result should be discarded) then the pointer will be to $D4:0.

 

String variables as arguments are pushed as three-byte pointers to either the string variable or literal string used in the procedure call. There will be no local string variable created. This means that if you have a definition like

PROC WriteString(STRING s)

called by

WriteString(s3) 

Then the local variable s will actually be a shadow of the variable s3 used in the call.

Link to comment
Share on other sites

Happy to report that as of this morning, arrays are fully functioning. Just need to tighten up the code to calculate the address of an element. At the moment it's doing a "*1" on byte and character arrays, and I need to special that.

  • Like 1
Link to comment
Share on other sites

  • 6 months later...
  • 5 months later...

Hello, everyone. Checking in. Work, "paying" writing, and some health concerns had slowed down this project but it's back up to full speed now.

 

Started finding bugs in assigning and referencing array elements, and in the process decided that my variable assignment routines had just become too unwieldy to debug, so I'm breaking them up and rewriting them.

 

After I have this bug sorted out I'm going to post the source I have so far for the PC-side compiler if anyone else wants to play around in it.

 

  • Like 4
Link to comment
Share on other sites

  • 2 weeks later...

Well, the problems I had been having before having to go work on the novel that now isn't going to come out (grr) have finally been resolved, and as promised I'm posting where I am at the moment. Then I will take a breath and get back to work again.

 

The problems I'd been having had to do with arrays, array references in procedure calls, and function calls as arguments of procedure/function calls. All working now at long last.

 

Coming up next, the compiler as it stands at this moment for those who want to play with it. It is EXTREMELY crude, but source is included. If there are interested parties I may set up a space for it at GitHub or someplace similar so others can join in the fun.

Link to comment
Share on other sites

This archive contains the source code and a Windows (x86 32 bit) executable for the compiler as it stands right now. As I said before, it is still extremely crude.

 

The source code is written in Lazarus, which is an open-source cross-platform development system designed to be compatible with Delphi. If you know Delphi, Lazarus is simple and free to download.

 

The executable version is bloated, I know, because I still have all the debugging information and such still in.

 

WHAT DOESN'T WORK:

 

Floating point variables not fully implemented. Considering dropping them altogether unless there is call to include.

Objects/classes and records not fully implemented. This is my next big project.

String arrays not yet implemented.

Pointers not fully implemented. This is coming shortly.

There is no RTL to speak of at this point. I will post the current state of the only RTL routines I've got at this point (mainly for printing) in an upcoming message.

 

WHAT DOES WORK:

 

Loops (FOR, WHILE, UNTIL)

Arrays (other than strings)

Procedure calls

Function calls

Bank switching

Code stored and run in banked memory

Variables stored in banked memory

 

Accomplish Compiler 0.1 pre alpha.zip

Link to comment
Share on other sites

PRINT.ACC - Printing runtime routines

//
// Accomplish Run-time routines needed for screen output.
//
// This is a band-aid. The final RTL will have better routines.
//

PROC StrC(CARD c,STRING POINTER s)
//
// Return the string representation (decimal) of card c in string "S"
//
[$A5$A0$85$CB$A5$A1$85$CC$A9$0A$85
 $CD$A9$00$85$CE$A9$00$85$AF$20
 !DIV $A6$AF$A5$D6$18$69$30$9D$80
 $04$E6$AF$A5$D4$85$CB$D0$EB$A5$D5
 $85$CC$D0$E5$A5$A2$85$D4$A5$A3$85
 $D5$A5$AF$AA$A0$00$91$D4$C8$BD$7F
 $04$91$D4$CA$D0$F7]
RETURN

PROC StrB(BYTE b,STRING POINTER s)
//
// Return the string representation (decimal) of byte b in string "S"
//
[$A5$A2$85$A3$A5$A1$85$A2$A9
 $00$85$A1$4C StrC]
END

PROC PutD(BYTE ICB,a)
//
// PUT the byte in a to the specified IOCB number.
//
 [$A5$A0$0A$0A$0A$0A$AA$A9$A1$9D$44
  $03$A9$00$9D$45$03$A9$01$9D$48$03
  $A9$00$9D$49$03$A9$0B$9D$42$03$20
  $56$E4]
RETURN

PROC PrintD(BYTE ICB, STRING s)
//
// Print string to specified IOCB
//
 [$A5$A0$0A$0A$0A$0A$AA$A5$A1$85$D4
  $9D$44$03$FE$44$03$A5$A2$85$D5$9D
  $45$03$A9$0B$9D$42$03$A0$00$B1$D4
  $9D$48$03$20$56$E4]
RETURN

PROC PrintDE(BYTE ICB, STRING s)
//
// Print string to IOCB, followed by EOL.
//
 [$20 PrintD $A9$9B$85$A1$4C PutD]
END

PROC Print(STRING POINTER s)
//
// Print string to IOCB #0
//
 [$A5$A2$85$A3$A5$A1$85$A2$A5$A0$85
  $A1$A9$00$85$A0$4C PrintD]
END

PROC PrintE(STRING POINTER s)
//
// Print string to IOCB #0 followed by EOL.
//
 [$20 Print $A9$00$85$A0$A9$9B$85
  $A1$4C PutD]
END

PROC PrintC(CARD c)
//
// Print CARD to IOCB #0
//
STRING str=$580
  StrC(c,str)
  Print(str)
RETURN

PROC PrintCE(CARD c)
//
// Print CARD to IOCB #0 followed by EOL.
//
STRING str=$580
  StrC(c,str)
  PrintE(str)
RETURN

PROC PrintB(BYTE b)
//
// Print BYTE to IOCB #0
//
STRING str=$580
  StrB(b,str)
  Print(str)
RETURN

PROC PrintBE(BYTE b)
//
// Print BYTE to IOCB #0 followed by EOL.
//
STRING str=$580
  StrB(b,str)
  PrintE(str)
RETURN

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...