6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sat Nov 23, 2024 5:25 am

All times are UTC




Post new topic Reply to topic  [ 48 posts ]  Go to page Previous  1, 2, 3, 4  Next
Author Message
PostPosted: Sun Mar 17, 2013 10:32 pm 
Offline

Joined: Sun Nov 08, 2009 1:56 am
Posts: 411
Location: Minnesota
Quote:
whatever the build process involves, it's likely more than simply an assembler,


Perhaps not much more. It's likely the process used for the Apple II works as it does because of the Apple II environment itself. The Merlin assembler writes code to an object buffer in memory (the OP might want to note the address of the object buffer has no connection whatever to the address the code is meant to run at). The thing is the buffer is not nearly large enough to hold a complete assembly of PoP. Merlin has pseudo ops for this situation - it's not uncommon in 64K environments - that allow whatever is currently in the buffer to be written to disk and the space re-used.

The comment regarding putting the buffer contents at specific track and sector locations is not, AFAIK, something Merlin does natively, but apparently there is a hook provided that allows custom code that could do it. I imagine the main reason for doing that is so later the running program can dispense with most or all of Apple DOS (thus reclaiming the memory space it requires) in favor of its own direct reads.


Top
 Profile  
Reply with quote  
PostPosted: Sun Mar 17, 2013 10:51 pm 
Offline

Joined: Tue Feb 26, 2013 2:59 pm
Posts: 27
Yes, that is roughly it. I've read through enough to understand that. The process would not have gotten rid of DOS or PRODOS though. That's needed to fetch the assembler and code from ordinary disks. At one point, JM had a hard disk and floppies. PRODOS remans resident to work from, while the 18 sector RTWS is there to output the product of the build to write protected disks, which is also where it runs from. So both exist in the machine, and that's why the code works in tracks and sectors. It's easiest that way as there literally is no DOS for the source code to reference, just tracks and sectors.

At run time then, it's only using that small 18 sector RTWS. Correct! Took me quite some time to understand Merlin and how that user hook was used.



Back then, it happened a lot like this:

1. Boot the Apple

2. Bload RTWS for 18 sectors

3. Setup user hook for Merlin to use

4. Test

5. Assemble, with Merlin building code in chunks, writing each one out to it's place on the disk as needed.

6. Repeat for other side of disk.

7. Optionally update assets.

Some tasks, like formatting new 18 sector disks to work from happened from Applesoft, and or the monitor, depending on what was needed. This is possible because Merlin can just build in the memory area it's given, meaning the program must be in chunks, but not too small of chunks, leaving just enough working room to support the 18 sector disks. No file names, nothing.

There are also some support programs there for doing various things, like capturing animation frames and arranging them for use on the graphics screen, level editing, etc... Those would run on the Apple as most things do, the outputs stored in binary images, or written directly to the 18 sector disk, if not included through Merlin at build time. Quite a complex affair.

It happened this way because the copy protected disks need to be written from the machine using the RTWS that creates them.

The end result is "assemble to disk image", which is then booted on a development Apple, or the same one, sadly requiring it all get setup again for the next build.

What will be required for a new build is precisely what Miles outlined. A standard RTWS, and I'm thinking of using the DOS 3.3 one, because it's out there, commented and standard, will need to be used in lieu of the 18 sector one.

The nice thing about that is it can just be included in a modern assembly, no special init or code running on a real Apple required. The not so nice thing is then going through the code, mapping out all the code and asset dependencies to understand the disk storage scheme will also be required.

Then the fun begins! Map out a new scheme and modify the code to fetch from that.

Which brings me back to this query. I now understand how it could be done with cc65, which would involve mapping segments to disk sectors, etc... That's less than optimal, given the method Miles outlined, which basically directs the assembler to build a disk image directly.

And personally, that kind of thing left unexplored is just annoying. It will nag at me for some time, because it has a lot of advantages over the other schemes I've encountered so far. That does not invalidate them. For real hardware that has banks, ROM, cartridges, etc... those are needed, useful, productive.

Worse, Miles hinted at doing it that way for Elite. So how did it happen? Which tool, or did he modify one, etc... ? It seems unreasonable to post up a method that cannot be duplicated. Perhaps he didn't know, or I've not yet learned what tool works, or it's commercial, etc... though I did check those where I could.

So, that's a basic matter to resolve before I start the long haul of getting code moved into a modern environment. I won't do well, probably fail, if I don't have the end result vetted before starting down a fairly long road.

Edit: Yes, of course! The assembly address was not always the run address. Sometimes it was though, but most of the time it was assembled to work at one address, built where there was room to do so in the Apple, then written to a track and sector on the disk to be fetched at run time.


Top
 Profile  
Reply with quote  
PostPosted: Mon Mar 18, 2013 2:52 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8544
Location: Southern California
I wrote the stuff below before your last post potatohead, and got interrupted before I could post, but it mostly seems to still apply. What does RTWS stand for?

In my earlier post, I thought you were talking about banking in hardware, where the program writes to an output port to select a window into a larger memory but the processor itself still thinks it's in the 0000-FFFF address range. Since I was so far off the mark, I've been holding off to see what else would come to light. With our aircraft products, I sometimes get calls from potential customers asking if they can do such-and-such, and it's nice to be able to surprise them that what they thought was a special application requiring their clever solution is really already designed in and the unit does the job without any special tricks applied. Other times, after I think I've seen and heard it all, someone asks for something that seems totally off the wall, yet after hearing them out, I find that they usually have a good reason for it, and fortunately I'm able to give them a way to do it with our products.

So after reading this whole topic again and yet a third time, I think I'm catching on. It seems like a really, really bad way to do things if actual track and sector numbers have to be related to execution address, but it sounds like you're saying that's what Apple II did, so it is what it is and you're stuck with it. I would hope that at this stage, ie, 30 years later with PCs with megabytes--even gigabytes--of RAM, a cross-assembler could do the whole thing in one gulp in a second or two, but then there's the job of how to get the product onto an Apple II disc. Is that it?

Quote:
I just spent the day peering at every single 6502 related cross assembler I could find. There are quite a number of them!

There's quite a list at http://www.npsnet.com/danf/cbm/cross-development.html, and I think not included there, is the HXA and P65 assemblers. I've been using the C32 assembler myself for the last 20 years, and previously used the 2500AD assembler. These links are all on the links page on my web site.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
PostPosted: Mon Mar 18, 2013 4:16 am 
Offline

Joined: Tue Feb 26, 2013 2:59 pm
Posts: 27
I'm Doug, BTW. I like my username, but it can be goofy in conversation sometimes. Hi Garth.

Well, I wrote it wrong: RWTS = Read Write Track Sector. It's the core bit of code needed to interact with the Apple ][ disk drive. The drive is a software driven device, with only a little bit of hardware assisting the 6502 in the task of using the disk storage. Most, if not all other disks I've encountered employ a controller of some sort to accomplish what the Apple ][ does in software.

An Apple has just enough in ROM to read a very small portion of a given floppy disk, and that portion then fetches the whole of the RWTS and the start up code for the DOS.

My understanding of this is still a work in progress, but as I understand it a given disk format scheme is associated with a specific RWTS code. Standard code, like for say DOS 3.3, does 16 sectors per track. The PoP code uses a custom RWTS that does 18 sectors per track, and in addition includes copy protection hackery that makes it difficult to make a copy of. This also made the B0rderbrund disks more efficient, allowing for better game assets, etc... as a nice positive for the user.

The product of that is an environment where a program can literally be built onto a bootable disk readable only by that program! Interesting stuff.

Miles actually communicated that very well, and his posts are a big help in understanding what happened to build that program. Without those comments, I would very likely be in the dark on it, moving on. But I think I get it.

Now, there isn't an association between execute addresses and disk tracks and sectors. PoP was written to utilize the disk as tracks and sectors though. No filenames, etc... Just the interface provided by the custom RWTS software, a missing piece today. What will need to happen is a build of the program that employs 16 sector RWTS, which will break some things. Actually most things, particularly those written to just read in an entire track very quickly in one go.

Before any real work begins, Miles did correctly assert that a working model needs to be created so that one can "assemble" to disk. He suggested one big file, though I believe that's a suggestion and perhaps not the best one. I don't know. What I do know at this stage is that I need to be able to assemble code "to the disk" and that's where the crux of the discussion is!

Spent the weekend looking at a ton of assemblers! That actually was a lot of fun, and there is an amazing number of 6502 related tools, none of which seem to complete the very lucid picture Miles created. And I'm kind of stuck on this because every other piece of information he provided has proven to be spot on!

From what I can tell, it's needing to work like this:

A disk is a linear sequence of bytes, starting with $0 and ending 140Kbytes later at $22FFF. Side two of that disk begins at $23000 and ends at $45FFF. A PoP disk is bigger than that due to the 18 sectors. Whether or not that takes three disks, or some space can be reclaimed remains to be seen. There are a couple of places in the PoP code that appear to blow a whole track for speed. Perhaps something can be done, or maybe it's gonna be a three disk affair. I don't know. Will be fun to get there though!

So that's the disk.

PoP was originally built in Merlin and each portion of it was assembled somewhere in the Apple //e RAM, and it was assembled there because that's where assembly could happen on the setup JM had. Nothing special there. Code either gets assembled where it's intended to execute, or it's assembled where it needs to be, intended to execute somewhere else. From what I can tell so far, this is a perfectly ordinary thing to do, given that "somewhere else" is actually within the 64K address space.

What I really need is for that "somewhere else" to simply be anywhere, not just within the 64K address space, and then I can carry forward given the methodology shared here. And that's compelling, because it makes a hell of a lot of good sense.

The product of that will be an assembly source code file that will "assemble to disk", directly building the disk image, and as far as I can tell, the only real difference between doing this and just doing it in the 64K address space is allowing for a target address larger than 64K. In every other way, it's ordinary enough that I find myself somewhat stunned that it's simply not out there possible to do.

An alternative that struck me today is to play a lot of games with segments and such so that there are a bunch of little 64K friendly bits of code built, kept track of, then piled together to form the disk image indirectly. This appears to involve defining a lot of little memory regions, then defining how they behave, then writing some scripts or describing how that all would combine to make a floppy disk for the linker part of the process.

For systems employing bank selection of large RAM, or ROM cartridge type storage devices, this makes a lot of sense! I get that, and since this kind of thing isn't done every day, I think I get why my queries here seem strange or maybe just really difficult to talk about.

If it's possible to do this with your products --or possible to make it possible, I'll give the project a go, and I'll write up what happens along the way too.

Again, to be really clear the necessary functionality is as follows:

1. Assemble code with an ORG that equals the intended execute address and an OBJ that can exceed 64K, and do that for 6502 / 65c02.


This may require defining some memory structure or other; otherwise, the software would have to just make a "virtual memory" kind of assumption requiring dynamic allocation of RAM, etc... It could be as simple as a linear storage definition with an upper boundary, 24 or 32 bits in size. Any disk then could be represented as bytes. The programmer would simply declare the upper boundary and optional fill value and proceed.

In fact, having that initialized to a value, say 0, would be extremely useful!

2. Be able to assemble a body of code consisting of multiple ORG statements and multiple OBJ statements.

3. Save the product to a file. Optionally, saving part of it to a file for the purpose of generating individual discrete disk images as part of the assembly process. However, just building it, then writing out the file is enough.

That's as clear as I'm capable of right now. :)


Top
 Profile  
Reply with quote  
PostPosted: Mon Mar 18, 2013 6:06 am 
Offline

Joined: Sat Oct 20, 2012 8:41 pm
Posts: 87
Location: San Diego
potatohead wrote:
Before any real work begins, Miles did correctly assert that a working model needs to be created so that one can "assemble" to disk. He suggested one big file, though I believe that's a suggestion and perhaps not the best one. I don't know. What I do know at this stage is that I need to be able to assemble code "to the disk" and that's where the crux of the discussion is!


I seems it would be difficult and unnecessary to assemble code straight to disk specifying tracks and sectors only. You don't need one big file, you normally save all, or part of the assembled code to a file and then load that binary file in memory somewhere and have some disk utility program write the binary code to the tracks/sectors that you desire. You would then be able to load back those sectors in any order to memory for execution. It does depend on the type of format that this 18 sector system uses but there are some Apple utility programs out there for writing to DOS 3.3 disk 256 byte sectors or in the case of Prodos it would be blocks (2 - 256 byte sectors).


Top
 Profile  
Reply with quote  
PostPosted: Mon Mar 18, 2013 6:19 am 
Offline

Joined: Tue Feb 26, 2013 2:59 pm
Posts: 27
Seems to me a few things are mixed together here.

There is what happened then. What happened then was code got assembled to RAM, and got written out to 18 sector disks, and it was written track and sector with a small routine called by the Merlin assembler. There was no DOS for the target media, which was just a formatted 18 sector disk. That may be difficult, and I think it is, but that also was the process they used to protect media and improve it's capacity at the same time. Successful builds resulted in disks that would only be read by the program contained on them, or some in-house utility programs not released for obvious reasons.

There is building on an Apple now, and I agree with you there. One could simply repeat the old build process with various utilities, though it would again be simpler to just do it track and sector style as originally done. Advancing that to file names, or a DOS proper would require code changes --significant ones. But, there is the fact that building directly on the Apple today is painful too. I'm not going that route at all. I want it to execute as a bootable disk on a real Apple, but I've no plans at all to build it on one.

What I'm targeting is a modern build process that will result in a bootable binary image. Plug that into ADT, write a disk with a real Apple, boot it, and play the game. Or, stuff that into an emulator and do the same.


Last edited by potatohead on Mon Mar 18, 2013 7:20 am, edited 2 times in total.

Top
 Profile  
Reply with quote  
PostPosted: Mon Mar 18, 2013 6:22 am 
Offline

Joined: Sun Nov 08, 2009 1:56 am
Posts: 411
Location: Minnesota
Quote:
play a lot of games with segments and such so that there are a bunch of little 64K friendly bits of code built,


Sorry, you're going to have to do that anyway. You can certainly build PoP as one big file exceeding 64K in size even without using that ability to think outside the address space so many assemblers lack. The "trick" here is simply periodically re-setting the program counter via ORG so that it never exceeds the 64K boundary. You can pack ten or a hundred or a thousand "segments" each 64K long, each starting at $0000 and ending at $FFFF, into one big object file assembled in one shot if you want. Just never let the program counter hit $10000.

As for the disk image, you may have to take that great big file the assembler generated and break it up with another tool into 256 byte chunks you can individually write to whatever track and sector you need. It may be worth pointing out that there may have been a financial as well as a technical reason for a custom 18-sector track: if the game can be packed onto one instead of two floppy disks, copies of the game don't cost so much to produce. Not much of a concern these days (though the memory space used by Apple DOS when PoP is actually running might still be).

I wonder if those "addresses" you refer to as being on the disk are actually something else. Floppy disks don't have addresses, just some count of sectors of some size. The "addresses" may be virtual, in the sense that PoP itself "thinks" in those terms - as locations or offsets within that "great big file" where things are found. That missing custom RWTS would have had the responsibility of mapping them into actual physical track and sector locations, ie., it would do the virtual-to-physical translation. That would have let PoP "think" about itself at a higher level of abstraction - as that attractive "one great big file".

If so a plus for you, since you wouldn't have to change anything PoP itself does if you substituted a different RWTS that performed a different translation (say, a 16-sector version over however many floppy disks that works out to).


Top
 Profile  
Reply with quote  
PostPosted: Mon Mar 18, 2013 6:38 am 
Offline

Joined: Sat Oct 20, 2012 8:41 pm
Posts: 87
Location: San Diego
With Merlin you could make a large file but I don't think you could write it using 18 sectors. It would write it in the currently loaded DOS format. Maybe the really old DOS versions had 18 sectors? I only used DOS 3.3 and Prodos so I'm not sure about that.


Top
 Profile  
Reply with quote  
PostPosted: Mon Mar 18, 2013 6:41 am 
Offline

Joined: Tue Feb 26, 2013 2:59 pm
Posts: 27
To be really clear, PoP refers to tracks and sectors when it access it's disk. What it does specifically is request that a given track and sector list be read into RAM at a specific address. That's it. The RWTS performs that task and only that task. A DOS for the Apple would overlay on top of that to provide filesystem support, etc... But there is no DOS when PoP is running. There is a DOS while it's building, and the bridge between that DOS and the target disk is the 18 sector RWTS code, which is resident and called by the assembler during build time to produce the finished program in the form of a bootable floppy disk readable by that program.

Let's talk about "that one big file" for a moment. Perhaps I'm missing something. Are you saying that I could author an assembly language body of code that when assembled will produce one huge file?

So I do an ORG and an OBJ, assemble, write it to a file, another ORG and OBJ, append to the file, etc...?

Which assembler and how? Edit: Ok, I get it. Use the "save" option some assemblers have, but can those append, or what? I'm curious to see even a fragment example of this happening on a named assembler so that I can start the work to get my bearings on said assembler.

That's not the same thing as being able to do an ORG and an OBJ directly into a specific byte offset in to the file, but much better than dealing with segments, banks and so forth. The sample Miles put on the thread would generate a bootable binary disk image. Assemble it, with god knows what at this point which I find completely bizzare for reasons already given, and the product of that assembly will then boot in an emulator. That same file, put through ADT would produce a bootable floppy bootable on a real Apple ][. That is the attraction.

From what I can tell PoP doesn't have that abstraction in it. What it does is call the RWTS with the track and sector list and a load start address. The RWTS fetches those sectors, deposits them where it was asked to, then returns to PoP, which continues on with the new data in place.


Last edited by potatohead on Mon Mar 18, 2013 7:22 am, edited 3 times in total.

Top
 Profile  
Reply with quote  
PostPosted: Mon Mar 18, 2013 6:42 am 
Offline

Joined: Tue Feb 26, 2013 2:59 pm
Posts: 27
@TeamTempest: Oh, and I just noted this: "even without using that ability to think outside the address space so many assemblers lack."

Can you cite even one that can? I looked really hard. :)

Sorry to be difficult. I don't mean to be. And I'm compelled by the fact that every other piece of information Miles contributed was spot on correct. Huge help. It's bizzare to me this ability is so difficult.

@ClockPulse: Well, yes you can. What JM did back then was BLOAD a usr routine to perform the 18 sector operations. If you go and look through the PoP code, that routine gets called repeatedly during a build and what it does is write the object code Merlin produces to a specific place on the 18 sector disk. That user routine could be fetched any time prior to assembly and either placed in a region of RAM that's not impacted by the Merlin assembler, or more likely a region protected by some sort of HIMEM statement to that assembler. Moot point though, unless somebody wants to knock out an 18 sector RWTS... Then a build on the Apple with few code changes could proceed actually.

...well, I should be clear. B0rderbrund could, JM could, others could. Today, that 18 sector code isn't available to us, nor is the copy protection bit, so we can't do it today, but it was possible to do, and was done then to produce bootable disks containing PoP.

This was a very tricky point to understand. I spent considerable time getting there. Frankly, the idea was foreign to me as every other computer I have used from that era had smarter floppy disk drives that had controllers to handle those things. The Apple ][ did all of that in software, meaning one could make any kind of disk they wanted to, and it would boot and be readable by the program that authored it, but not generally by other standard programs.


Last edited by potatohead on Mon Mar 18, 2013 7:03 am, edited 2 times in total.

Top
 Profile  
Reply with quote  
PostPosted: Mon Mar 18, 2013 6:59 am 
Offline

Joined: Tue Feb 26, 2013 2:59 pm
Posts: 27
Completely agreed on the financials. Packing it onto one disk was actually cited as a strong point in the journal JM put out there to read.

Efficiency was also cited. Disks held more and were fast, due to that RWTS code being very good code.


Top
 Profile  
Reply with quote  
PostPosted: Mon Mar 18, 2013 9:17 am 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10986
Location: England
I think part of the problem here is thinking of ORG as an address. It's not an address, it's a destination. In the original Apple story, it's a destination on disk. In a modern cross-assembling story, it's one of two things:
- an offset into a single big file which is a disk image. You are strtuggling to find an assembler which does this.
- a filename - one of many files you will write, each under 64k in size, which you will subsequently collect into a disk image.

It would be helpful, I think, to distinguish the steps which already have standard names:
- assemble, takes source and outputs code stream which we'll call object files
- link, takes collections of object files and produces a single file which we'll call an executable
- load, takes the single executable and places it in memory and jumps to some address

In your case, there's some variation:
- the executable you want is actually a disk image, or two or three of them
- you need a step which places the disk images onto a disk or three, together with a boot block which contains your RWTS
- the initial loading is done by your boot block code
- subsequent overlay loading is done by your application, using sector addresses (maybe track and sector addresses)

Cheers
Ed


Top
 Profile  
Reply with quote  
PostPosted: Mon Mar 18, 2013 10:07 am 
Offline
User avatar

Joined: Tue Mar 02, 2004 8:55 am
Posts: 996
Location: Berkshire, UK
I coded support for big address spaces into As65 but I haven't tested it thoroughly.

To build an application like PoP you would need to assemble the overlays into different banks using .ORG commands with 24-bit addresses (e.g. $01xxxx, $02xxxx, etc.).

When you run the linker you specify the region of code you want put into the output file. If you run the linker multiple times you could produce binary files for each overlay region in addition to the main memory by changing the region address each time.

You'd have to figure out how to assemble the binary files into the final disk image.

_________________
Andrew Jacobs
6502 & PIC Stuff - http://www.obelisk.me.uk/
Cross-Platform 6502/65C02/65816 Macro Assembler - http://www.obelisk.me.uk/dev65/
Open Source Projects - https://github.com/andrew-jacobs


Top
 Profile  
Reply with quote  
PostPosted: Mon Mar 18, 2013 9:40 pm 
Offline

Joined: Sat Dec 13, 2003 3:37 pm
Posts: 1004
So, just to catch up, are you trying to duplicate the build process on an Apple //e? Or are you trying to take code that was originally built on some Apple based dev system, and then create an Apple compatible disk? Are you going to run this on a simulator? Port the code someplace else? Are you trying to build this on a PC using cross assemblers?


Top
 Profile  
Reply with quote  
PostPosted: Mon Mar 18, 2013 11:54 pm 
Offline

Joined: Sun Nov 08, 2009 1:56 am
Posts: 411
Location: Minnesota
Quote:
Let's talk about "that one big file" for a moment. Perhaps I'm missing something. Are you saying that I could author an assembly language body of code that when assembled will produce one huge file?



Yes.

Quote:
So I do an ORG and an OBJ, assemble, write it to a file, another ORG and OBJ, append to the file, etc...?


This is one place you keep losing me. I don't understand why you want to do that. Why not just assemble the whole thing and then write it out as one big block? What problem are you trying to solve that can only be accomplished by periodically saving some portion of the assembly - when you want to end up with one big block anyway?

Most cross-assemblers should allow you ORG, assemble some code, ORG again, assemble again, ORG again, assemble again, etc, as often as you like. As long as you don't let the assembler's program counter ever get outside the processor address space there shoudn't be any problem. When you've had enough of that, then the result gets written as one big file. Multiple ORGS. One OBJ.

Quote:
Can you cite even one that can?


Nope. I would think that the sheer fact that you can't find any assembler that does what you consider so simple might be a clue that at the very least, it's not a feature most programmers have found a need for.

If you're bound and determined to do that anyway, perhaps the best you can do with existing tools is adopt BitWise's suggestion to use an assembler that can handle the 65816, with its 24-bit address space. Just be sure not to use any 65816-specific instructions (the assembler won't know or care if you don't).


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 48 posts ]  Go to page Previous  1, 2, 3, 4  Next

All times are UTC


Who is online

Users browsing this forum: No registered users and 17 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: