Jump to content
IGNORED

IntyBASIC compiler v1.0 crunchy&tasty :)


nanochess

Recommended Posts

Yeah, I've already learned to avoid using signed 8-bits for precisely that reason. It doesn't work like you'd expect it to. Now I just check for >255 or similar, which works better.

 

 

If you do want to store signed values in 8-bit variables, you can sign extend cheaply with ((var XOR 128) - 128).

Link to comment
Share on other sites

Hey, Oscar, for the next version can you add a new keyword to change the name of the game in the final rom to something other than the default "IntyBASIC" that is in the

intybasic_prologue.asm

 

I'm changing it manually before I compile (or at least I will before final releases,) but once LTO Flash is out we are going to have a bunch of roms in the menu with the same name if other programmers are unaware of this.

 

Thanks to Intysteve for saying something in another place that reminded me to ask.

  • Like 1
Link to comment
Share on other sites

Hey, Oscar, for the next version can you add a new keyword to change the name of the game in the final rom to something other than the default "IntyBASIC" that is in the

intybasic_prologue.asm

 

I'm changing it manually before I compile (or at least I will before final releases,) but once LTO Flash is out we are going to have a bunch of roms in the menu with the same name if other programmers are unaware of this.

 

Thanks to Intysteve for saying something in another place that reminded me to ask.

 

 

TITLE would be my vote. It's been suggested before. For now we have to deal with it manually.

 

Yep, the request is still in my list, but I'm trying to find a way to integrate it.

 

My main problem is that intybasic_prologue.asm is included before compilation starts. So I'm thinking in a command-line argument.

Link to comment
Share on other sites

Yep, the request is still in my list, but I'm trying to find a way to integrate it.

 

My main problem is that intybasic_prologue.asm is included before compilation starts. So I'm thinking in a command-line argument.

 

That'd be OK, at least it would avoid having a bunch of copies of prologue.asm lying around. I guess there's no way to override code in the prologue from within a .bas file?

 

My (very weak) understanding is that stuff in epilogue.asm is included/excluded in the final .asm based on what commands are used in the .bas file. Could TITLE be moved into epilogue.asm? Does the concept even make sense?

  • Like 1
Link to comment
Share on other sites

I was just having a PM convo with Intysteve, spurred on by his working on the menu software for the LTO Flash! wherein he has several IntyBasic roms on his LTO and they all have the same "IntyBASIC program", name when the code reads the TITLE from the rom (which it does when there is no matching rom in the database.)

 

post-38229-0-19644900-1422053875_thumb.jpg

 

Appears to be the worst case.

 

What about splitting intybasic_prologue.asm into two files?

intybasic_header.asm

intybasic_prologue.asm

 

        ;
        ; Title, avoid and jump directly into main program
        ;
_TITLE: PROC

;end of Intybasic_header.asm

;build and insert the following at compile time based on COPYRIGHT and TITLE keywords, values of which
;would not default and would throw a compiler error unless the keywords were used.

        BYTE    114, 'IntyBASIC program', 0

;start of Intybasic_Prologue.asm
;        BEGIN


;        RETURN                  ; Return to EXEC for title screen display
        ENDP


        ;
        ; Main program
        ;

 

Again, I have no problem changing it myself as each project gets it's own copy of the compiler and .asm files, but if we can head the problem off at the pass before the LTO comes out...

 

  • Like 1
Link to comment
Share on other sites

 

That'd be OK, at least it would avoid having a bunch of copies of prologue.asm lying around. I guess there's no way to override code in the prologue from within a .bas file?

 

My (very weak) understanding is that stuff in epilogue.asm is included/excluded in the final .asm based on what commands are used in the .bas file. Could TITLE be moved into epilogue.asm? Does the concept even make sense?

Think about the prologue and epilogue as "library" modules that you include during compilation. Except that those are libraries for the assembler. Like with any compiler, by the time a library is imported, the assembler is already engaged.

 

Since the name of the final output binary file is defined in the assembler's command line, putting it in the library files does not help.

 

What you need is to include it in the configuration parameters if the IntyBASIC compiler. At the moment, there is no file for this, just command line options.

 

dZ.

Link to comment
Share on other sites

Think about the prologue and epilogue as "library" modules that you include during compilation. Except that those are libraries for the assembler. Like with any compiler, by the time a library is imported, the assembler is already engaged.

 

Since the name of the final output binary file is defined in the assembler's command line, putting it in the library files does not help.

 

 

(Keep in mind that I am 99% ignorant of how this works)

 

Then it's the assembler that decides which parts of the library files to include? I'm basing my thinking on the observation that my final assembled file can be much larger in size, simply by including a single BASIC command (things like MUSIC or VOICE). So I assumed that means that something (either the compiler or assembler) is seeing that keyword/function call, and then saying "ok, gotta include this relevant code".

 

Couldn't TITLE trigger a similar behaviour? Have a default, but replace/override it if the .bas file has TITLE in it? Or is part of the problem that we must have the _TITLE: PROC already there in order for the assembler to get started with its piece? Does some of this have to do with it being 2 different programs/steps written by 2 different people?

 

(Keep in mind that I am 99% ignorant of how this works)

 

Another thought... IntyBASIC does its magic and generates an .asm file. Could the very last step be "hey, TITLE was set in the source code - do a search/replace in the output .asm with whatever the programmer wants"? I already had an inkling to insert this step in my compilation script but figured it was way too hacky. Just parse the .bas for TITLE, store the value, then use sed or something similar to modify the .asm just before calling as1600.

 

Also keep in mind that I'm referring to TITLE only in the sense of what ends up IN the final binary (and displayed in the emulator/LTO Flash! menu). Not the filename of the binary itself. THAT is obviously controlled outside of the programs, and for good reason.

Edited by freeweed
Link to comment
Share on other sites

Yep, the request is still in my list, but I'm trying to find a way to integrate it.

 

My main problem is that intybasic_prologue.asm is included before compilation starts. So I'm thinking in a command-line argument.

 

 

Just take the current _TITLE out of intybasic_prologue.asm entirely, and emit a _TITLE record from your code generator.

 

In other words, simply delete this:

.

_TITLE: PROC
        BYTE    114, 'IntyBASIC program', 0

.

And replace it with code in the compiler that runs just before including intybasic_epilogue.asm that does something like this:

.

_TITLE:   DECLE  115, "Title string", 0
          JD     _MAIN

.

... where 115 and "Title string" are pieces that vary depending on what the compiler saw. (And take out the DIS at _MAIN, as JD will disable interrupts for you.)

 

Set a default year and title string internally to the code generator. (Bonus points: Set the default year to the current date, and the default name to the name of the source file, sans ".bas".) If you encounter a TITLE statement, update that year and title. At the end of code generation, emit the _TITLE record ahead of bringing in intybasic_epilogue.asm.

 

There is absolutely NO requirement on the address that holds the cartridge title and year, other than that it's ROM visible at reset. (So, for Mattel-style paged ROM, it needs to be page 0.) That's it. The title string and year can otherwise appear anywhere in the memory map as long as the cartridge header at $5xxx points to it.

 

The only cost of doing it this way is an extra "JD" in the startup path (which you can offset slightly by removing the DIS at _MAIN), and the 2 words codesize incurred.

Edited by intvnut
  • Like 1
Link to comment
Share on other sites

 

That'd be OK, at least it would avoid having a bunch of copies of prologue.asm lying around. I guess there's no way to override code in the prologue from within a .bas file?

 

My (very weak) understanding is that stuff in epilogue.asm is included/excluded in the final .asm based on what commands are used in the .bas file. Could TITLE be moved into epilogue.asm? Does the concept even make sense?

 

 

IMO, the _TITLE record should not be in either intybasic_prologue.asm or intybasic_epilogue.asm.

 

Part of the issue is this: nanochess uses an EXEC backdoor to boot into IntyBASIC games, and I think that's influenced the design more than it should have. (I use this very same backdoor. It's a very, very nice backdoor, and I would never ever fault anyone for using it. But understanding the backdoor helps us understand the current situation.)

 

The backdoor works like this: By setting bit 7 of the 'keyclicks byte' in the ROM header, you tell the EXEC that you have a "title screen fixup routine." The role of the title-screen fixup routine is to touch up the default EXEC title screen with additional flourishes, if necessary. (For example, printing additional copyright lines for licensed titles.) The fixup code must appear immediately after the terminating NUL in the title string. That's the 'in': By requesting a 'title screen fixup,' the EXEC will jump to the code just after the title string. We put our init code there and take over the machine. Profit!

 

So, if you look at intybasic_prologue.asm, this sequence may make a bit more sense now:

.

        ;
        ; Title, avoid and jump directly into main program
        ;
_TITLE: PROC
        BYTE    114, 'IntyBASIC program', 0
;        BEGIN

;        RETURN                  ; Return to EXEC for title screen display
        ENDP

        ;
        ; Main program
        ;
_MAIN:
        DIS
        MVII #STACK,R6

.

If you ignore the bit of commented-out schizophrenia with BEGIN/RETURN and a comment about returning to display the EXEC title screen, you can see that we fall into _MAIN immediately after the title string. Edited for conciseness, this is what the EXEC and CP-1610 CPU see (and in the end, the neither of those care about the label "_MAIN"; rather, the CPU just falls into that code because it's after the title string):

.

_TITLE:  BYTE    114, 'IntyBASIC program', 0
_MAIN:   DIS
         MVII #STACK,R6

.

I believe it's this co-location that's giving nanochess heartburn. The date/title string need to be right before _MAIN, and _MAIN needs to be at the very top of the ROM, and all of these things need to fall sequentially into each other.

 

If you allow yourself one extra branch—and nanochess, I think you've earned it, so take that extra branch! ;) ;) ;)—then you can relocate the title string to anywhere, and once you do that, it can be something that the IntyBASIC compiler itself can output directly. That's my suggestion as per my previous post.

Edited by intvnut
  • Like 2
Link to comment
Share on other sites

Oh! You are referring to the title string that is fed to the EXEC to compose the TITLE SCREEN, this thing?

_TITLE: PROC
        BYTE    114, 'IntyBASIC program', 0

I think the perceived problem is that it is statically defined in the "prologue" library file that gets included at the very top of the generated assembly file, which comprises the ROM header required by the Intellivision EXEC (the built-in OS, which we only use as a "boot-loader"). This means that, by the time the compiler engages, the library has already been injected into the output stream.

 

However, it should be easy to fix. One cheesy way that I can think of is to accept a "TITLE" statement, and if the compiler detects it, it can store the STRING data, and replace the pointer in the ROM header.

        ; --------------------------
        ; Patch TITLE string pointer
        ; (The cheap and easy way!)
        ; --------------------------
_pcaddr QSET  $          ; Keep track of current program counter
        ORG   $500A      ; Location of pointer in header
        DECLE $XXXX      ; Pointer to new title string
        ORG   _pcaddr    ; Restore program counter

Since the above code saves and restores the program counter, the code generator can inject it at any point in the source, and as many times as it needs to (if the idiot programmer used the TITLE statement multiple times). Of course, only the last one will reign supreme.

 

-dZ.

  • Like 1
Link to comment
Share on other sites

.

I believe it's this co-location that's giving nanochess heartburn. The date/title string need to be right before _MAIN, and _MAIN needs to be at the very top of the ROM, and all of these things need to fall sequentially into each other.

 

If you allow yourself one extra branch—and nanochess, I think you've earned it, so take that extra branch! ;) ;) ;)—then you can relocate the title string to anywhere, and once you do that, it can be something that the IntyBASIC compiler itself can output directly. That's my suggestion as per my previous post.

 

By the way, that's what P-Machinery does: it sets the title screen and copyright (based on values provided by the programmer in the initial "start" statement) and then branches into a BOOT routine where the original title screen is fixed (and we put a REAL copyright symbol!), the state machine is initialized and engaged, and a few other house-warming duties are performed. Profit! :)

 

 

post-27318-0-39367900-1422103396_thumb.gif <-- Click to enlarge

That screen is generated by this code:
;;==========================================================================;;
;; Title:       P-Machinery Test Driver                                     ;;
;; By:          DZ-Jay                                                      ;;
;; Description: A simple test driver of the P-Machinery game engine.        ;;
;;                                                                          ;;
;;==========================================================================;;
;; Copyright © 2014, James Pujals (DZ-Jay), <dz-game@techunlimited.net>.    ;;
;;==========================================================================;;

;; ======================================================================== ;;
;; PROGRAM SET-UP                                                           ;;
;; ======================================================================== ;;

                INCLUDE "mac/mac_prog.mac"

                PROG.Start "P-MACH TEST", "DZ-Jay", 2014

                    ; Initialize state machine
                    LIB.Include  "tests/test-io_dec.asm"
                    STATE.SetInitial(Title, Wait)

                PROG.End

;; ======================================================================== ;;
;;  END OF LINE.                                                            ;;
;; ======================================================================== ;;
 
  • Like 2
Link to comment
Share on other sites

There's an old "Hello World" tutorial created by Valter Prette that explained line-by-line the Universal Data Block (UDB), a.k.a. the ROM header. The tutorial itself is rather terse, and suffers (like many other Intellivision-related documents) from being too low-level and close to the hardware to be useful to anybody but dedicated hackers; but the UDB description at least is good.

 

(looking, looking, looking...) Aha! Found it!

 

WhitePaper-Intellivision Programming 2.pdf

  • Like 1
Link to comment
Share on other sites

By the way, print statements in P-Machinery are encapsulated with automatic alignment. For instance, the title above was defined like this:

TXT.PrintAlign("The P-Machinery AGE", Center, 3, CS.White)
From the source documentation:

;;  TXT.PrintAlign(str, align, row, color)                                  ;;
;;  Prints a text string onto the screen and aligns it horizontally on the  ;;
;;  row based on the specified argument "align."                            ;;
;;                                                                          ;;
;;  ARGUMENTS                                                               ;;
;;      str         The string to print.                                    ;;
;;      align       The horizontal alignment to use.  Available values are: ;;
;;                      Left    Left justified.                             ;;
;;                      Right   Right justified.                            ;;
;;                      Center  Center justified.                           ;;
;;                                                                          ;;
;;      row         The screen row at which to print the string.            ;;
;;      color       The text color to use for output.                       ;;

There's also a convenient "PrintAt()" directive, so that you can align the string yourself:

;;  TXT.PrintAt(str, col, row, color)                                       ;;
;;  Prints a text string onto the screen coordinates specified by the "col" ;;
;;  and "row" arguments.                                                    ;;
;;                                                                          ;;
;;  ARGUMENTS                                                               ;;
;;      str         The string to print.                                    ;;
;;      col         The screen column at which to print the string.         ;;
;;      row         The screen row at which to print the string.            ;;
;;      color       The text color to use for output.                       ;;

Link to comment
Share on other sites

Hmmmm. Very good ideas :) :thumbsup:

 

I didn't knew the exact requirements for the address of title data nor the exact behavior to jump into main code.

 

Well, now you know that bit of magic behind the cart header. :-)

 

jzIntv actually picks up the ROM name and year from the ROM header to set as its window title. I picked up the trick from Carl Mueller Jr's DOS-based launcher for INTVPC many, many moons ago. And, LTO Flash! will use this to identify new games also.

 

If you have any questions on fiddly details, let me know. I'm an email or PM away.

 

Eventually, I'd like to be able to embed additional metadata in a compiled game. So, if we get the TITLE thing figured out and it works well, then maybe we can go from there.

  • Like 1
Link to comment
Share on other sites

Pf. I'm a huge fan of the original "incorrect" copyright symbol. Nothing to me screams Intellivision like "@ 2015". :D

 

Are you saying I should consider this:

 

post-14113-0-67890800-1422129591_thumb.gif

 

Instead of this?

 

post-14113-0-39410000-1422129696_thumb.gif

 

(click second one for animation goodness.)

Edited by intvnut
  • Like 2
Link to comment
Share on other sites

Oh! You are referring to the title string that is fed to the EXEC to compose the TITLE SCREEN, this thing?

_TITLE: PROC
        BYTE    114, 'IntyBASIC program', 0

I think the perceived problem is that it is statically defined in the "prologue" library file that gets included at the very top of the generated assembly file, which comprises the ROM header required by the Intellivision EXEC (the built-in OS, which we only use as a "boot-loader"). This means that, by the time the compiler engages, the library has already been injected into the output stream.

 

However, it should be easy to fix. One cheesy way that I can think of is to accept a "TITLE" statement, and if the compiler detects it, it can store the STRING data, and replace the pointer in the ROM header.

        ; --------------------------
        ; Patch TITLE string pointer
        ; (The cheap and easy way!)
        ; --------------------------
_pcaddr QSET  $          ; Keep track of current program counter
        ORG   $500A      ; Location of pointer in header
        DECLE $XXXX      ; Pointer to new title string
        ORG   _pcaddr    ; Restore program counter

Since the above code saves and restores the program counter, the code generator can inject it at any point in the source, and as many times as it needs to (if the idiot programmer used the TITLE statement multiple times). Of course, only the last one will reign supreme.

 

-dZ.

 

 

Using a label in the cartridge header is sufficient. ie. just say "BIDECLE _TITLE" and let the assembler populate the address. No need to use ORG tricks to overwrite a BIDECLE when defining a label will do nicely. (And yes, it's a BIDECLE in the header, not a DECLE. Those are rare beasts in 16-bit ROMs. The UDB, however, was built for 10-bit ROM.)

 

The real issue is ensuring that the code that follows the title branches to the _MAIN program. With nanochess' syntax driven translation approach, each executable statement gets translated to assembly code immediately when seen, as it's seen.

 

As proposed, it doesn't seem like TITLE is really an executable statement. It's really more of a metadata statement. So, unless you want to force TITLE to be the very first statement of a BASIC program, it needs a different code generation strategy. That's why I suggested a "stash and emit-at-end" strategy, which remains largely consistent with the syntax driven translation approach.

  • Like 1
Link to comment
Share on other sites

 

As proposed, it doesn't seem like TITLE is really an executable statement. It's really more of a metadata statement. So, unless you want to force TITLE to be the very first statement of a BASIC program, it needs a different code generation strategy. That's why I suggested a "stash and emit-at-end" strategy, which remains largely consistent with the syntax driven translation approach.

 

Er, wouldn't patching the BIDECLE with a new pointer with the ORG trick do that at the point of finding the TITLE statement in the source?

Link to comment
Share on other sites

 

Well, now you know that bit of magic behind the cart header. :-)

 

jzIntv actually picks up the ROM name and year from the ROM header to set as its window title. I picked up the trick from Carl Mueller Jr's DOS-based launcher for INTVPC many, many moons ago. And, LTO Flash! will use this to identify new games also.

 

If you have any questions on fiddly details, let me know. I'm an email or PM away.

 

Eventually, I'd like to be able to embed additional metadata in a compiled game. So, if we get the TITLE thing figured out and it works well, then maybe we can go from there.

 

Thanks!

 

I really try to solve things on my own for learning purposes before asking for help :) also to save yourself some time so you can bring us LTO faster ;)

  • Like 1
Link to comment
Share on other sites

 

Er, wouldn't patching the BIDECLE with a new pointer with the ORG trick do that at the point of finding the TITLE statement in the source?

 

How is that different than letting the assembler do it for you through ordinary symbol resolution?

 

If I say:

.

        BIDECLE  _TITLE

; ... several kilobytes of code

_TITLE: STRING 115, "My Game", 0

.

With no further effort on my part, the assembler will correctly put the address of _TITLE into the BIDECLE.

 

I could overwrite the BIDECLE like so, since AS1600 lets you, but why would I?

.

b:      BIDECLE $0000

; .... several kilobytes of code

_TITLE: STRING 115, "My Game", 0

tmp:    EQU $
        ORG b
        BIDECLE _TITLE
        ORG tmp

.

Both give exactly the same result, but one of them is significantly less hack-y.

 

I tend to reserve such hacks for things that actually need them, due to phase ordering issues. This is a case that simply doesn't need such a hack.

 

 

My point about TITLE being a non-executable statement is that if IntyBASIC generated code for TITLE immediately where it sees it, it would have to also put a branch around it in the code. For example, suppose I wrote this:

.

    PRINT "Hello World"
    TITLE 2015, "Hello World"
    WAIT
    REM  rest of game here

.

With the pure syntax translation approach IntyBASIC uses, if TITLE output code immediately, you'd end up with assembly code like this:

.

        ;FILE /tmp/h.bas
        ;[1]
        SRCFILE "/tmp/h.bas",1
        ;[2]     PRINT "Hello World"
        SRCFILE "/tmp/h.bas",2
        MVI _screen,R4
        MVII #320,R0
        XOR _color,R0
        MVO@ R0,R4
        XORI #872,R0
        MVO@ R0,R4
        XORI #72,R0
        MVO@ R0,R4
        MVO@ R0,R4
        MVII #632,R0
        XOR _color,R0
        MVO@ R0,R4
        XORI #632,R0
        MVO@ R0,R4
        XORI #440,R0
        MVO@ R0,R4
        XORI #960,R0
        MVO@ R0,R4
        XORI #232,R0
        MVO@ R0,R4
        XORI #240,R0
        MVO@ R0,R4
        XORI #64,R0
        MVO@ R0,R4
        MVO R4,_screen
        ;[3]     TITLE 2015, "Hello World"
        SRCFILE "/tmp/h.bas",3
        B T1
_TITLE: STRING 115, "Hello World", 0
        JD _MAIN
T1:
        ;[4]     WAIT
        SRCFILE "/tmp/h.bas",4
        CALL _wait

.

For code that executes once, that extra branch-around is fine. And, if the programmer didn't include TITLE, you'd have to add some code in intybasic_epilogue.asm to output a default:

.

    IF (DEFINED _TITLE) = 0
_TITLE: STRING 115, "IntyBASIC", 0
        JD _MAIN
    ENDI

.

But, you can avoid all that entirely by having IntyBASIC always output a title record at the end of code generation. Also, you can avoid assembly errors if someone is silly enough to have multiple TITLE statements, by just remembering the last one.

 

I'm not sure you quite grok the problem I'm trying to solve. And I fail to see the problem the ORG-warp solves that isn't addressed through normal two-pass assembly label resolution.

Edited by intvnut
  • Like 1
Link to comment
Share on other sites

My point about TITLE being a non-executable statement is that if IntyBASIC generated code for TITLE immediately where it sees it, it would have to also put a branch around it in the code.

 

 

 

And my point is that, if you do the ORG hack, you don't need to branch around. What am I missing?

 

Never mind. My solution needs the code generator to put the string at the end as well, so the hack buys you nothing. You are right.

Edited by DZ-Jay
Link to comment
Share on other sites

 

 

And my point is that, if you do the ORG hack, you don't need to branch around. What am I missing?

 

Never mind. My solution needs the code generator to put the string at the end as well, so the hack buys you nothing. You are right.

 

I was gonna say.... I didn't see how that was possible. :)

 

Now, if you want to use the ORG hack to overwrite a default title in-place (ie. overwrite an actual string with another actual string), you could maybe make that work. But, that requires reserving a fixed amount of space for the title, which seems... short sighted.

Edited by intvnut
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...