6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sun Sep 08, 2024 2:13 am

All times are UTC




Post new topic Reply to topic  [ 45 posts ]  Go to page 1, 2, 3  Next
Author Message
PostPosted: Mon Sep 12, 2005 10:38 am 
Offline
User avatar

Joined: Fri Dec 12, 2003 7:22 am
Posts: 259
Location: Heerlen, NL
Hallo allemaal,


CP/M enabled a lot of people to run the same software on may different computers as long as they were equiped with a Z80 or Intel 8080. There are many 6502 (or equivalent) equiped computers around. Some of you are even building new ones. What would be nicer then building a new computer and having tons of software available right from the start?

Is this worth a discussion?

I'm awaiting your comment.

_________________
Code:
    ___
   / __|__
  / /  |_/     Groetjes, Ruud
  \ \__|_\
   \___|       URL: www.baltissen.org



Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Tue Sep 13, 2005 2:17 am 
Offline

Joined: Wed Jul 20, 2005 11:08 pm
Posts: 53
Location: Hawaii
The Z80 and 8080 processors are 8 bits. That would make it easy to port to the 6502. If anyone could find the assembly source for CP/M for the 8080, I could probably port it.

_________________
Sam

---
"OK, let's see, A0 on the 6502 goes to the ROM. Now where was that reset vector?"


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Tue Sep 13, 2005 9:55 am 
Offline
User avatar

Joined: Fri Dec 12, 2003 7:22 am
Posts: 259
Location: Heerlen, NL
asmlang_6 wrote:
The Z80 and 8080 processors are 8 bits. That would make it easy to port to the 6502. If anyone could find the assembly source for CP/M for the 8080, I could probably port it.


You'll find sources at http://www.gaby.de/ but if it is just a matter of translating sources, I or anyone else could have done it years ago. The way files are loaded in memory and how the memory is treaten has everything to do how a Z80 handles memory. And a 6502 isn't a Z80. CP/M 3.0 is supports memory banking but it can only handle 15 extra banks of 32 KB and the way it is done doesn't cheer me up either, certainly if seen from the point of view of a 6502.

The idea of this OS (a nice name, anyone?) is that it should run on various existing hardware and hardware yet to be build. CP/M requires a minimum of at least 16 KB AFAIK. 3.0 needs at least 48 KB. And my VIC-20 only has 5 KB on board.....
But CP/M needs the RAM to be able to load the OS from disk. So one goal can be to support ROM versions of the OS, either in the forms of ROMs that replace the original ones or ROMs that are added to system using a free socket (like the C= CBM's have) or a cartridge (C64, C128, VIC-20).

If a CP/M program wants to output a byte to the floppydisk, harddisk, videoscreen or whatever, it stores the byte somewhere and calls a vector. This vector then leads to the machine dependant part that does the wanted actions. What has to be done is to define all needed vectors. We can use CP/M as base but DOS has many more then CP/M and therefor is a better base to start with. Do we need all those vectors DOS is using? I don't know and in fact I don't care. The idea is to dreamup a mechanism that allows me to use various number of vectors. (OTOH, 65536 vectors should be enough IMHO)

But supporting a lot of vectors means a big OS, one may think. A text only computer (like the C= CBM 8032) doesn't need OS support for a GUI. IMHO it is just a matter using some directives that tell the assembler what parts to include or not. Another idea, load the needed part from disk (or whatever) execute it and discard it again (like DOS does).

CP/M has its own filesystem. Should we define our own one as well? Yes and no. No because, for example, I want to be able to play my C64 games under the new OS as well. In case of Commodore an extra problem is that it is not the computer but the drive that defines how and where data is stored on a disk. It is possible to define your own layout but IMHO it is not worth the trouble. Certainly if you know that, for example, a Acorn BBC or Electron is unable to read the floppies of a C= (and vica versa).
Yes, because we should be able to exchange data. My idea: most computers I know off have a RS-232 port. We can program the OS so that it treats this particular port as another drive. We connect a PC to this port that runs a program that emulates a (hard)disk using an image. And we need this Filesystem for this emulated disk.

Points to discuss:
- vectors
- filesystem
- handling of the available memory
- page swapping
- ???

Now you may shoot :)

_________________
Code:
    ___
   / __|__
  / /  |_/     Groetjes, Ruud
  \ \__|_\
   \___|       URL: www.baltissen.org



Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Tue Sep 13, 2005 7:40 pm 
Offline

Joined: Sat Jan 04, 2003 10:03 pm
Posts: 1706
Ruud wrote:
And a 6502 isn't a Z80. CP/M 3.0 is supports memory banking but it can only handle 15 extra banks of 32 KB and the way it is done doesn't cheer me up either, certainly if seen from the point of view of a 6502.


It pretty much is a matter of just translating assembly sources, actually. CP/M was ported to a number of processors that equally aren't memory layout compatible with the Z-80 (68000 comes to mind!). The question is, however, does anyone *WANT* such an OS? I wager to think no, or else someone would have provided one. I think Apple's ProDOS comes the closest, but I understand that there was (until the Apple IIgs at least) a lot of opposition around it.

Quote:
The idea of this OS (a nice name, anyone?) is that it should run on various existing hardware and hardware yet to be build. CP/M requires a minimum of at least 16 KB AFAIK. 3.0 needs at least 48 KB. And my VIC-20 only has 5 KB on board.....


Use GEOS/64 for an inspiration. 8KB for the core kernel, DOS, and event-driven architecture. And that's the key: make it event driven by design, and ruthlessly avoid redundancy. I'll get more into this below.

Quote:
If a CP/M program wants to output a byte to the floppydisk, harddisk, videoscreen or whatever, it stores the byte somewhere and calls a vector. This vector then leads to the machine dependant part that does the wanted actions. What has to be done is to define all needed vectors. We can use CP/M as base but DOS has many more then CP/M and therefor is a better base to start with.


I strongly recommend using a microkernel-like architecture, so that the proliferation of "kernel" API calls are minimized. I seem to recall reading that Acorn OS did something much like this. This style of kernel design is also strongly recommended for other reasons:

* Fewer OS calls means it's smaller, and therefore more ROM friendly.

* Fewer OS calls and semantics means fewer bugs, and therefore, less ROM revisions.

* Fewer OS calls makes for a more flexible architecture, if the OS calls are orthogonal with respect to each other. For example, the OS called Plan-9 is able to do nearly EVERYTHING that it does using only open(), read(), write(), and close(). There are a few other system calls, but they're used far less often. Even graphics are handled this way.

Quote:
Do we need all those vectors DOS is using? I don't know and in fact I don't care. The idea is to dreamup a mechanism that allows me to use various number of vectors. (OTOH, 65536 vectors should be enough IMHO)


If you're so hell-bent on having a huge proliferation of vectors, I recommend instead the AmigaOS-style library system, where libraries supply their own vectors. To call a function:

Code:
; First, open the library, so that we can access it
; elsewhere.

    lda #<libName
    sta $00
    lda #>libName
    sta $01
    lda #libVersion
    sta $02
    jsr SysOpenLibrary  ; one of the few global OS calls
    bcc couldNotOpenLibraryForSomeReason
    lda libBase
    sta myLibBase+1
    lda libBase+1
    sta myLibBase+2

; Now let's make a few calls to it.

    ... ; load parameters somehow here.

    ldx #MYLIB_FUNC_1
    jsr myLibBase

    ldx #MYLIB_FUNC_2
    jsr myLibBase

; Here's where we store the library "entry points", so to speak.

myLibBase:
    jmp $0000

yourLibBase:
    jmp $0000
    ...


Now a library would need a convenient way to decode the function ID that is in the X register:

Code:
    ORG LibraryLoadAddress

entryPoint:
    jmp (myTable,X)

myTable:
    dw  func1
    dw  func2
    dw  func3
    ...etc...


This way, vectors are kept library-specific, and take up space only for the modules that are currently loaded.

Quote:
CP/M has its own filesystem. Should we define our own one as well?


MUCH more important is not the filesystem proper, but the interface to a filesystem. Installable filesystems are damn handy to have, and makes the specific choice of filesystem less relavent.

Quote:
No because, for example, I want to be able to play my C64 games under the new OS as well. In case of Commodore an extra problem is that it is not the computer but the drive that defines how and where data is stored on a disk. It is possible to define your own layout but IMHO it is not worth the trouble.


Experience has shown that Commodore's layout is sorely suboptimal. Especially for devices with slow seek times, you want a filesystem that is optimized to minimize fragmentation whenever possible. Also, its layout does not permit subdirectories, often strongly desired even on small storage devices for organization.

The only thing that Commodore DID get right is the placement of the root directory blocks and the BAM on the center cylinder.

Quote:
- vectors


I feel they should be provided by the modules loaded into the system and managed by a core foundation. A single pool of vectors, no matter how big, will always be inefficient (too few vectors used in the system, or too many to remember, or. . .).

A better solution still might be instead to make use of message passing between multiple tasks in a (perhaps cooperatively) multitasking system, and build the core operating system as a microkernel.

However, the problem with this approach is that you're providing a leaky abstraction: you're trying to convince the programmer that his code more or less has ownership of the machine as a whole, and therefore, every program tends to be written as if it were initializing itself, running its own event loop, etc. This leads to *MASSIVE* code replication -- something a 6502 system can do without!

Instead, building an event-driven architecture is perhaps the best overall choice. Code written for the OS takes the form of a large collection of callbacks, which are invoked by the OS in response to certain stimuli. The benefits of this are many:

* A single, system-wide event queue and kernel dispatcher, which eliminates all the duplication from all the other programs designed to run under it.

* Can "multitask" without explicit support for multitasking. It can do this because the system-wide event queue can interleave events for multiple programs. The performance will be comparable to cooperative multitasking, without all the overhead of task switching. Sophisticated kernels can even profile how long it takes to handle a specific event handler, and can implement fairness algorithms based on this if necessary (probably only on a 65816, where enough memory can exist to support this). Kernels optimized for more sophisticated processors (e.g., a 65816, or an emulated 6502/65816 environment hosted on a more sophisticated processor) can provide real multitasking easily enough.

* 80% of all software today spend 80% of their time waiting for something to happen. Remember that back when Unix and VMS were invented, computers were built for batch-processing of work, not human interaction. Today, the situation is reversed. Therefore, it seems that optimizing the OS to support the most common occurance will make for a more space- and time-efficient OS architecture. GEOS/64 proved this quite nicely!

* Compute-heavy tasks can be supported by a number of mechanisms:

+ Submit an event for a single loop iteration to kick off the loop. The loop iteration handler then will, if necessary, submit another event for itself. Thus, the loop self-perpetuates until such time it is done (in which case it just doesn't re-issue its own event).

+ Register an Idle handler so that the OS periodically calls it while waiting for something to arrive in the event queue.

+ Support true multitasking of some sort, and run the compute-heavy tasks as background processes.

* Event-driven architectures can scale to multitasking or multiple processor architectures relatively easy. OS-supplied shims can be inserted transparently between the application and the core kernel to support these features transparently. Commercial distributed object middleware libraries and standards like DCOM, MTS, and CORBA make regular use of things called "thread pools," which satisfies all the requirements for an event-driven architecture of this nature.

As a clear example of this style of OS, look no further than GEOS/64. GEOS API is big and bulky, but nonetheless demonstrates the power of having a system-wide event queue. I wish I had another example, but unfortunately a design prototype I implemented in Linux one day can't be found. As far as commercial examples, look at some of the more sophisticated Enterprise JavaBeans implementations, or CORBA or DCOM/MTS "thread pools" implementations.

Quote:
- filesystem


While it'd be nice to have one, there are plenty off-the-shelf FSes to choose from. I recommend the LEAN filesystem http://freedos-32.sourceforge.net/showdoc.php?page=leanfs.

Quote:
- handling of the available memory
- page swapping


These can be unified. The application can dynamically manage memory using memory allocation and deallocation functions. PC/GEOS demonstrated that this concept can also apply towards allocating space in a disk file to emulate memory. Once allocated, the memory can be locked or unlocked (brought into memory or released from memory, respectively) as required, allowing the memory manager to efficiently swap memory segments from or to disk as required. In fact, PC/GEOS application data files are just virtual address spaces!! This is why PC/GEOS was obnoxiously fast on a 8088 when we still have to wait 30+ seconds for Word to open an office document on a Pentium 4 with hyperthreading.

Hopefully, I've provided food for thought on this issue. I strongly advocate a consistent OS architecture. While I am a huge fan of Forth for OS-level interaction, I recognize that not everyone wants this. If I were to accept a more traditional OS architecture, this is what I'd want to see.

Note, however, that a microkernel approach, where multiple tasks exchange messages with each other, is perhaps *the* ideal solution, but it requires support for preemptive multitasking, at the very least. I strongly urge folks to study the L4 microkernel for inspiration in this area. It has something like 12 to 14 system calls, and that is it. The two most frequently used are SEND and RECEIVE, used to send and receive a message, respectively.

SEND will block the calling task until its message is received. RECEIVE will block until a message becomes available. No message queues -- you send directly to task IDs. Thus, memory consumption is *constant* (unlike the event driven architecture I pointed out above), and if you can load a program into memory, you can NEVER run out of memory due to excessive message passing.

But, again, it requires preemptive multitasking at the very least.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Tue Sep 13, 2005 8:58 pm 
Offline
User avatar

Joined: Wed Sep 03, 2003 6:53 pm
Posts: 153
Location: Long Island, NY
asmlang_6 wrote:
The Z80 and 8080 processors are 8 bits. That would make it easy to port to the 6502. If anyone could find the assembly source for CP/M for the 8080, I could probably port it.


Although I haven't done an exhaustive comparison of the two processors, I believe that just translating the CP/M sources won't work. I have some minor experience through my Altair Emulator project which has both an 8080 and Z80 emulation.

Yes, all three processors are 8-bit and have a 64k address space but there are several critical differences which will make direct translation almost impossible:

Stack: the 6502 has the stack in a fixed location and a fixed size. The 8080/Z80 stack can be initialized to any address and can grow beyond 256 bytes.

Vectors: the 8080/Z80 have 8 software vectors called restart vectors (RST0 to RST7) which occupy the first 64 bytes of the address space. One can place a short routine in each and execute it by issuing the one-byte RST instruction.

Instructions: the 8080/Z80 has many instructions which have no analogue in the 6502 (the RST instruction is a good example)

Registers: the 8080/Z80 have four pairs of 16-bit registers (AF, BC, DE, HL) which are also byte-addressible, in addition to the stack pointer and instruction registers. The Z80 adds two index registers and a number of "prime" registers (i.e., BC') in the same number as the base registers. I confess that I'm not as well-versed on the Z80 as I am with the 8080 but the fact remains that the 8080/Z80 have way many more registers than the 6502.

I/O: The 8080/Z80 use port-mapped I/O while the 6502 is memory mapped I/O.

Examining the CP/M sources, it becomes evident that since CP/M uses many of the things that comprise the differences between the two processor architectures, direct translation would be impossible.

Now, one solution would be to design a standard Z80 daughter card and software like the Commodore Z80 cartridge or the Apple Z80 Card that can be used with homebrew designs.

Rich

_________________
Rich Cini
Build Master and maintainer of the Altair32 Emulation project
http://cini.classiccmp.org
http://altair32.classiccmp.org


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Tue Sep 13, 2005 11:37 pm 
Offline

Joined: Sat Jan 04, 2003 10:03 pm
Posts: 1706
RichCini wrote:
Although I haven't done an exhaustive comparison of the two processors, I believe that just translating the CP/M sources won't work.


This is a given, no matter what the program, no matter what the processor. I don't think what "translating sources" means is an instruction-by-instruction transliteration. That'd be foolish. A function-by-function translation, however, is much more capable, and is precisely how DRI ported CP/M from the 8080 environment to the 68000 and later to the 8086.

Quote:
Stack: the 6502 has the stack in a fixed location and a fixed size. The 8080/Z80 stack can be initialized to any address and can grow beyond 256 bytes.


This is not a problem in practice. The BIOS/BDOS would be located in upper memory anyway, leaving all of lower memory available for applications. Zero page and stack is considered part of the transient program, just as the "Program Segment Prefix" is considered part of an MS-DOS program.

Quote:
Vectors: the 8080/Z80 have 8 software vectors called restart vectors (RST0 to RST7) which occupy the first 64 bytes of the address space. One can place a short routine in each and execute it by issuing the one-byte RST instruction.


The 6502 has a BRK instruction which can, under software control, take a one-byte operand, thus offering up to 256 software-dispatched vectors.

However, this is irrelavent, as CP/M applications tend not to use RST vectors, but rather load parameters into registers and issue a CALL 5 instruction. The 6502 can do the same, loading X with the offset of a jump table, and issuing something like a JSR $0000.

Quote:
Instructions: the 8080/Z80 has many instructions which have no analogue in the 6502 (the RST instruction is a good example)


RST is a poor example; BRK is its analog.

Quote:
Registers: the 8080/Z80 have four pairs of 16-bit registers (AF, BC, DE, HL) which are also byte-addressible, in addition to the stack pointer and instruction registers. The Z80 adds two index registers and a number of "prime" registers (i.e., BC') in the same number as the base registers. I confess that I'm not as well-versed on the Z80 as I am with the 8080 but the fact remains that the 8080/Z80 have way many more registers than the 6502.


Irrelavent as CP/M tended to store 90% of its function call parameters in memory in the form of various "control blocks." Additionally, the 6502's zero page is usually used and is treated as if it were a set of 256 8-bit wide registers, which can be paired up to 128 16-bit wide registers. With proper coding practices, the (dp,X) addressing mode can provide a method for invoking OS functions re-entrantly. CP/M is not reentrant.

Quote:
I/O: The 8080/Z80 use port-mapped I/O while the 6502 is memory mapped I/O.


False; the 8080/Z80 *CAN* use port-mapped I/O, but often times also uses memory-mapped I/O (TRS-80 anyone?). Moreover, you're not going to use port-mapped I/O to stuff the video frame buffer, now are you?

And remember, the 68000 also lacks port I/O, relying also on memory-mapped I/O. I believe that the majority of the Commodore 128's I/O were also port-mapped, even when using CP/M mode.

Quote:
Examining the CP/M sources, it becomes evident that since CP/M uses many of the things that comprise the differences between the two processor architectures, direct translation would be impossible.


Also false. The BDOS module is quite possible to port, as only the BIOS is responsible for hardware-specific system interaction.

Quote:
Now, one solution would be to design a standard Z80 daughter card and software like the Commodore Z80 cartridge or the Apple Z80 Card that can be used with homebrew designs.


Thus defeating the whole purpose of the exercise. If we wanted a Z-80 running the OS of the system, we'll build our systems with Z-80s, and circumvent the whole 6502 architecture completely. As it is, we're interested in the 6502, not the Z-80.

However, CP/M is a pretty poor example OS to follow anyway. While architecturally trivial, it is equally self-limiting. All the major advancements in CP/M required major kernel rewritings, and those introduced software incompatibilities for all but the most rigorously CP/M 1.0-compliant programs.

If you want a good quality OS architecture, use a microkernel, and implement a few, basic primitives that are easy to implement and quite orthogonal. On top of the microkernel, a proper subset of the POSIX API would be a good point for inspiration. While not many people might agree that "everything can be treated as a file," it nonetheless has proven itself time and time again, from OSes like OS-9 to Lunix. open() can connect your program with another, read() and write() are used to communicate with said program, and close() is used to terminate that connection. poll() can be used to monitor multiple connections if you choose to implement asynchronous interprocess communications. Alternatively, you can implement a fleet of threads, one per source of input, and coordinate with a master thread. The advantage of the latter, synchronous system is that memory consumption is predictable and has hard limits, and it's easier to preserve message boundaries when sending data between running programs. This latter approach is more useful for 65816 systems, however, where more memory to support the larger thread pool is allowed.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Wed Sep 14, 2005 2:05 am 
Offline
User avatar

Joined: Wed Sep 03, 2003 6:53 pm
Posts: 153
Location: Long Island, NY
kc5tja wrote:

Quote:
Vectors: the 8080/Z80 have 8 software vectors called restart vectors (RST0 to RST7) which occupy the first 64 bytes of the address space. One can place a short routine in each and execute it by issuing the one-byte RST instruction.

The 6502 has a BRK instruction which can, under software control, take a one-byte operand, thus offering up to 256 software-dispatched vectors.


I'm familiar with the existence of the BRK instruction but wasn't aware of the "operand" capability.

Quote:
Instructions: the 8080/Z80 has many instructions which have no analogue in the 6502 (the RST instruction is a good example)

RST is a poor example; BRK is its analog.


Again, I didn't do an exhaustive comparison, but there probably are some instructions available in the 8080/Z80 that are not available in the 6502. Maybe there are fewer differences than I think.

Quote:
Registers: the 8080/Z80 have four pairs of 16-bit registers (AF, BC, DE, HL) which are also byte-addressible, in addition to the stack pointer and instruction registers. The Z80 adds two index registers and a number of "prime" registers (i.e., BC') in the same number as the base registers. I confess that I'm not as well-versed on the Z80 as I am with the 8080 but the fact remains that the 8080/Z80 have way many more registers than the 6502.

Irrelavent as CP/M tended to store 90% of its function call parameters in memory in the form of various "control blocks." Additionally, the 6502's zero page is usually used and is treated as if it were a set of 256 8-bit wide registers, which can be paired up to 128 16-bit wide registers. With proper coding practices, the (dp,X) addressing mode can provide a method for invoking OS functions re-entrantly. CP/M is not reentrant.


I agree with CP/M's non-reentrancy. I don't know about your statement regarding the use of Z-page memory. My point of reference is the early Commodore machines which by in large did not utilize the space that way. Maybe the later ones did.

Quote:
I/O: The 8080/Z80 use port-mapped I/O while the 6502 is memory mapped I/O.

False; the 8080/Z80 *CAN* use port-mapped I/O, but often times also uses memory-mapped I/O (TRS-80 anyone?). Moreover, you're not going to use port-mapped I/O to stuff the video frame buffer, now are you?


I should clarify. The 8080/Z80 can use both port-mapped and memory mapped I/O but only the 6502 can use memory-mapped I/O. You correctly point out that the BIOS can be re-written to accommodate any hardware. Video display boards like the Solid State Music V1B used memory-mapped I/O as did the Cromemco Dazzler. Before those boards, one only had serial boards to communicate through and those were accessed through port I/O.


Quote:
Examining the CP/M sources, it becomes evident that since CP/M uses many of the things that comprise the differences between the two processor architectures, direct translation would be impossible.

Also false. The BDOS module is quite possible to port, as only the BIOS is responsible for hardware-specific system interaction.


See clarification above.

Quote:
Now, one solution would be to design a standard Z80 daughter card and software like the Commodore Z80 cartridge or the Apple Z80 Card that can be used with homebrew designs.

Thus defeating the whole purpose of the exercise. If we wanted a Z-80 running the OS of the system, we'll build our systems with Z-80s, and circumvent the whole 6502 architecture completely. As it is, we're interested in the 6502, not the Z-80.


OK. I was attacking it from the point that it would be more difficult to re-write the BIOS, which was written for a different architecture, to fit another, than it would be to create a small daughter board and use a stock CP/M 2.2 distribution with I/O customization the same way one would modify the stock BIOS to work with his particular hardware configuration.

_________________
Rich Cini
Build Master and maintainer of the Altair32 Emulation project
http://cini.classiccmp.org
http://altair32.classiccmp.org


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Wed Sep 14, 2005 3:37 am 
Offline

Joined: Wed Jul 20, 2005 11:08 pm
Posts: 53
Location: Hawaii
Ruud wrote:
You'll find sources at http://www.gaby.de/ but if it is just a matter of translating sources, I or anyone else could have done it years ago. The way files are loaded in memory and how the memory is treaten has everything to do how a Z80 handles memory. And a 6502 isn't a Z80. CP/M 3.0 is supports memory banking but it can only handle 15 extra banks of 32 KB and the way it is done doesn't cheer me up either, certainly if seen from the point of view of a 6502.

A 6502 isn't a Z80, but that's the point of porting: to translate a program.

Ruud wrote:
The idea of this OS (a nice name, anyone?) is that it should run on various existing hardware and hardware yet to be build. CP/M requires a minimum of at least 16 KB AFAIK. 3.0 needs at least 48 KB. And my VIC-20 only has 5 KB on board.....

I'll target an old version. And I'll call the 6502 version CP/M-65. A good system to port to would be the Apple ][, which is perfect as it can be expanded to, guess what, 48 KB, and has quite a bit of memory from the start. Another good system to target would be the C64.

_________________
Sam

---
"OK, let's see, A0 on the 6502 goes to the ROM. Now where was that reset vector?"


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Wed Sep 14, 2005 4:00 am 
Offline

Joined: Sat Jan 04, 2003 10:03 pm
Posts: 1706
Quote:
I'm familiar with the existence of the BRK instruction but wasn't aware of the "operand" capability.


The 6502 has always treated the BRK instruction as a two-byte opcode; however, it was never documented as such until the Western Design Center revealed the 65C02. The rationale was that, since the overwhelming majority of instructions on the 6502 were 16-bits in size (opcode + ZP reference), a single byte could be used to patch EPROMs with RAM-resident software. Pretty slick, but over the years its use changed to that of a software interrupt function.

Quote:
I agree with CP/M's non-reentrancy. I don't know about your statement regarding the use of Z-page memory. My point of reference is the early Commodore machines which by in large did not utilize the space that way. Maybe the later ones did.


Not OSes supplied by Commodore at least. However, that's how many Forth environments work, choosing to implement the return stack using the CPU's native hardware stack, and the data stack using dp,x and (dp,x) addressing modes.

A common practice on the 65816 is to overlap the stack and direct page, which opens up still more interesting possibilities for high-level languages like C and Pascal/Oberon. When used in this mode, the D register forms the equivalent of a frame base pointer register, while the S register continues to serve as the regular stack pointer, leaving X open for application use. Pretty slick stuff. :)

Quote:
OK. I was attacking it from the point that it would be more difficult to re-write the BIOS, which was written for a different architecture, to fit another, than it would be to create a small daughter board and use a stock CP/M 2.2 distribution with I/O customization the same way one would modify the stock BIOS to work with his particular hardware configuration.


I actually don't think this would be the case overall; EhBASIC has already been ported to a number of existing 6502 systems, both homebrew and commercial. I suspect that the I/O routines found in EhBASIC would make a great basis for planning a BIOS implementation.

The only thing that would remain to be designed from scratch would be the disk I/O interface, but even here, IDE drivers are usually very (trivially, even) simple to implement for polled I/O. 6502.org has a few IDE interface projects that include sample code too.

Personally, I think the hardest part of the OS architecture will be identifying devices by name, and choosing between single-letter names (e.g., A:, B:, etc), multi-letter names (e.g., CON:, PRT:), or using a unified namespace (e.g., /dev/con, /MyDisk/MyDir/MyFile.txt). I'm generally a fan of the unified approach, but my AmigaOS background allows me to accept the multi-character label approach too. I really am not a fan of single-letter IDs for things.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Wed Sep 14, 2005 1:09 pm 
Offline
User avatar

Joined: Fri Dec 12, 2003 7:22 am
Posts: 259
Location: Heerlen, NL
Hallo kc5tja,


> The question is, however, does anyone *WANT* such an OS?

I merely see it as a FUN project.


> I wager to think no, or else someone would have provided one.

I can imagine there was no need in those days for whatever reason. But with not so many 6502 machines around these days, it means that with writing an application under such an OS you reach more people then writing an application for a specific machine.


> I strongly recommend using a microkernel-like architecture,

Haven't any idea what this means. I grew up with Commodore and MS-DOS so I'm a bit norrow minded.


> If you're so hell-bent on having a huge proliferation of vectors,

I called it "vector" as used by Commodore by lack of another name.


> I recommend instead the AmigaOS-style library system, where libraries
> supply their own vectors. To call a function:

IMHO just calling a vector inside another vector. Like calling a subfunction of INT $10, the software interrupt that handles all things that have to do with video under MS-DOS. Inserting a VGA card means that the system will use the routines provided by the card rather then the ones provided by the BIOS.
Hmm, a better example would be using INT $21, the MS-DOS interrupt.


> This way, vectors are kept library-specific, and take up space only for the
> modules that are currently loaded.

I want a compact OS, not one that needs to load a certain library if the circumstances require that. With the VIC-20 in mind: using a ROM based OS you cannot load another library when needed. OTOH, Commodore always provide a JMP ($xxxx) in their vectors where $xxxx is situated in RAM. This enables a program to bend/use a vector for its own purposes. CP/M and DOS placed their vectors in RAM as well enabling programs to do the same trick.


> MUCH more important is not the filesystem proper, but the interface to a
> filesystem.

Agreed. I had the own FS puely in mind for exchanging data through a PC. But even that is important. I use a PC as an external drive for my Commodores. The only commands a C= issues are commands like "LOAD", "SAVE", "PUT", "GET" etc., all FS independant commands. In these commands you have the interface you are looking for. And that enabled me to attach an 80 GB floppydrive to my CBM 8032 :)
FYI: I must admit that it is possible to target specific tracks and sectors on a floppy. Simulating the C= FS this is possible for 'floppies' up to 16 MB. When accessing a bigger drive, my simulator ignores this command.


> Also, its layout does not permit subdirectories,

Wrong, the FS itself permits it but that most drive don't support it, that's something else. If you want to know more about it, ask me.


> Instead, building an event-driven architecture is perhaps the best overall
> choice.
+
> As a clear example of this style of OS, look no further than GEOS/64.
> GEOS API is big and bulky,

IMHO indeed too bulky.

It is not that I only want an universal OS for the 6502, I also want to learn from it. I intend to start with "MS-DOS 1.0" and grow to "Windows XP" gradually (learning from the errors MS made of course).


> ... allocating space in a disk file to emulate memory.

Virtual memory, haven't thought about that as so yet. But OTOH VM can be seen as a special form of bankswitching: instead of swapping memory, data is swapped between memory and drive.


> Hopefully, I've provided food for thought on this issue.

Yep, you did :)


> If you want a good quality OS architecture, use a microkernel, and ....
> ..... poll() can be used ...

Sounds a bit like the IEEE protocol the Commodores use to exchange data with their peripherals what I'm familiar with. And therefor sounds good :)



> Personally, I think the hardest part of the OS architecture will be
> identifying devices by name, and choosing between single-letter names
> (e.g., A:, B:, etc), multi-letter names (e.g., CON:, PRT:), or using a
> unified namespace (e.g., /dev/con, /MyDisk/MyDir/MyFile.txt). I'm generally
> a fan of the unified approach, but my AmigaOS background allows me to
> accept the multi-character label approach too. I really am not a fan of
> single-letter IDs for things.

Never thought about this. But I tend to choose for the unified approach as well.



Hallo Sam,

> And I'll call the 6502 version CP/M-65.

I have thought about that as well but then a user will expect commands like DIR, PIP, ED etc. and the looks of CP/M like a A> prompt etc. Anyway thanks for the input.


> A good system to port to would be the Apple ][, ... and has quite a bit of
> memory from the start.

I want it to be able to run systems with just a bit of memory, maybe as low as 2 KB.

_________________
Code:
    ___
   / __|__
  / /  |_/     Groetjes, Ruud
  \ \__|_\
   \___|       URL: www.baltissen.org



Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Wed Sep 14, 2005 7:20 pm 
Offline

Joined: Sat Jan 04, 2003 10:03 pm
Posts: 1706
Quote:
IMHO just calling a vector inside another vector. Like calling a subfunction of INT $10, the software interrupt that handles all things that have to do with video under MS-DOS. Inserting a VGA card means that the system will use the routines provided by the card rather then the ones provided by the BIOS.
Hmm, a better example would be using INT $21, the MS-DOS interrupt.


No, it's nothing like this at all. The INT interface is fixed by one party only. Nobody can create their own APIs if they wanted to. Not, that is, without running into the possibility of colliding with someone else's (remember the hell of installing and managing TSRs in early DOS? Remember the *rediculously* complex method for resolving TSR API conflicts?)

The advantage of libraries is that anyone can write them and, upon loading, are treated precisely the same way as OS-standard libraries.

However, since the 6502 lacks memory protection hardware, you can probably get the same level of performance by creating virtual devices that programs can just open(), read(), write(), and close(). For example:

Code:
   ; I'm avoiding showing error checking because it's irrelavent
   ; to the expression of my idea.

   ; Open the clock handler

   lda #<ClockName
   ldx #>ClockName
   ldy #OpenFlags
   jsr Open
   sta clockHandle

   ; Ask it for the current wall clock time

   tax
   lda #'G   ; "G"et current time
   jsr WChar

   ; Now we receive the results.

   lda clockHandle
   ldx #<resultBuffer
   ldy #>resultBuffer
   jsr SetBuffer

   ldx #<bufferLength
   ldy #>bufferLength
   jsr SetLength

   jsr RBuffer

   ; We're done, so we might as well just close the clock device

   lda clockHandle
   jsr Close


In this case, the kernel-resident functions include Open, WChar, SetBuffer, SetLength, RBuffer, and Close. These would be statically vectored (like CBM kernel functions; and yes, kernEl is the proper spelling. :) ). I note that a number of DOS drivers worked this way as well, such as the earlier mouse drivers. Also, MSCDEX works this way to some extent; while it provides some INT $21 functions, other functions are accessible by reading/writing to MSCD0001 virtual file.

Quote:
> This way, vectors are kept library-specific, and take up space only for the
> modules that are currently loaded.

I want a compact OS, not one that needs to load a certain library if the circumstances require that. With the VIC-20 in mind: using a ROM based OS you cannot load another library when needed.


AmigaOS proves you wrong on this account. On all Amiga computers except the Amiga 1000, AmigaOS was stored in ROM, not in RAM. Yet it was every bit as able to use ROM-resident libraries as it was to use RAM-resident.

Granted, though, I doublt you'll be able to pull this off in any meaningful way with only 2KB RAM available. Here, you'll need to make a tradeoff between expressive power versus compactness.

Quote:
OTOH, Commodore always provide a JMP ($xxxx) in their vectors where $xxxx is situated in RAM. This enables a program to bend/use a vector for its own purposes. CP/M and DOS placed their vectors in RAM as well enabling programs to do the same trick.


AmigaOS library jump-tables are a generalization of the jump-tables used in Commodore's previous operating systems. AmigaOS provided a function called SetFunction() (in exec.library, the Amiga's microkernel), which was used to patch any library vector, including ROM-resident libraries. This function was how Commodore was able to boot-strap Kickstart 2.00-2.03 in an already running Kickstart 1.3 environment for the Amiga 3000 series of machines. Kickstart 2.04 was the first version of 2.0 to appear in its own ROM.

But, this is pretty much academic at this point. If your target computer is a VIC-20, then you'll want to go with a file-structured interface and support installable, virtual files and maybe even virtual directories if you've got the space for it.

Quote:
FYI: I must admit that it is possible to target specific tracks and sectors on a floppy. Simulating the C= FS this is possible for 'floppies' up to 16 MB. When accessing a bigger drive, my simulator ignores this command.


I'm aware of this, as well as the ability for a program to be able to download custom software into the drives for remote execution. This is how GEOS got 7x performance increase for the 1541 drives.

Quote:
> Also, its layout does not permit subdirectories,

Wrong, the FS itself permits it but that most drive don't support it, that's something else. If you want to know more about it, ask me.


Commodore never defined a standard for managing directories, nor any standard disk layout for them. Note that the Commodore 1581 concept of "partitions" do NOT count as directories -- like harddrive partitions, they create multiple logical virtual disk drives. They do not grow or shrink as needed. Once created, that's it -- they're however big you made it and you'll just have to be happy with that (until you scratch it and re-create it yourself of course). The fact that they can be accessed by name instead of by partition number is a quick bandaid hack for being able to access them in some meaningful manner.

Quote:
It is not that I only want an universal OS for the 6502, I also want to learn from it. I intend to start with "MS-DOS 1.0" and grow to "Windows XP" gradually (learning from the errors MS made of course).


Excellent -- I strongly encourage the journey to anyone. It's a frustrating, but very enlightening, trip to make.

What I was saying is to make an OS with a centralized event management and distribution system. GEOS is an example of this kind of philosophy. It is not the end-all, be-all of such operating systems. I've already outlined other examples, including CORBA and DCOM/MTS, which are domain-specific implementations of the concept.

GEOS is bulky because it's not orthogonal. It is lumping GUI code, FS code, and event management code, all into a single, static, monolithic kernel. If you want a system that is easy to learn, easy to hack, easy to maintain, then you need to use a microkernel. Keep the kernel small, efficient, and managable. Everything else is implemented as loaded or ROM-resident modules that is *clearly* distinct from the core kernel. Yes, it takes up some extra space for the linkage, but you'll be MUCH happier with the result.

If it's one thing I've learned, OSes are NOT simple programs. :)

Quote:
Virtual memory, haven't thought about that as so yet. But OTOH VM can be seen as a special form of bankswitching: instead of swapping memory, data is swapped between memory and drive.


That's where Lock() and Unlock() functions in PC/GEOS come in -- they perform the actual swapping. If a block of memory has been changed, you need to remember to mark it as Dirty() so that the swapper knows to write back the modified data to disk.

Note to Forth programmers: Lock() is analogous to BLOCK. Dirty() is analogous to UPDATE. There is no precise mapping of Unlock() to Forth, because Forth requires the application to use BLOCK to get its base address at all times; hence, blocks are inherently "unlocked" in Forth. Fortunately, most Forth systems are cooperatively multitasking at best, and so do not require explicit locking of blocks. However, if anything, FLUSH is the closest relative to Unlock(). Forth has no dynamically allocated blocks by default, so no standard analogs of Allocate() and Free() either.

Quote:
Sounds a bit like the IEEE protocol the Commodores use to exchange data with their peripherals what I'm familiar with. And therefor sounds good :)


It is very much like it. Commodore had a file-centric OS interface long before Plan 9. However, it's possible that Commodore got the idea from Unix, since Unix did predate Commodore PETs by about 10 years (1969 versus 1979). Where Plan 9 is better than CBMDOS, however, is the fact that it properly supports directories. In fact, this is a critical requirement for Plan 9, because without it, there is no way to issue commands to normal files (Plan 9 does NOT have an ioctl(), fcntl(), or sockctl() API interface; this is done instead by opening a separate channel such as /dev/filectl or something, and issuing commands through that interface instead). In fact, in Plan 9, each running program has its own filesystem namespace. So, program A's /dev/mouse might not be the same thing as program B's /dev/mouse.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Mon Sep 19, 2005 8:47 am 
Offline

Joined: Thu Jan 16, 2003 12:55 pm
Posts: 64
Location: Indianapolis
For an OS, are you all familiar with Contiki? http://www.sics.se/~adam/contiki/
I would try to use it if I was able to compile an NES version with cc65. :?

Ruud wrote:
My idea: most computers I know off have a RS-232 port. We can program the OS so that it treats this particular port as another drive. We connect a PC to this port that runs a program that emulates a (hard)disk using an image. And we need this Filesystem for this emulated disk.


I think that's a great idea. I've been wanting to create a setup just like this (except using the PC's native filesystem rather than a disk image, but that's mostly because I thought it'd be easier). I wrote out a little spec sheet last year with various commands for controlling it, I'll try to find it if you want to see my take on the idea. But I'm not sure how to write it as a PC program. I'd be willing to help write the 6502-side of something like this though, definitely.

For now I'm simply using XMODEM, which works well, but it's not usually fun to switch constantly between using my PC and my 8-bit. At least if I use YMODEM I think I won't have to type filenames anymore, but it still requires some human intervention.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Mon Sep 19, 2005 3:42 pm 
Offline

Joined: Tue Nov 18, 2003 8:41 pm
Posts: 250
Quote:
My idea: most computers I know off have a RS-232 port. We can program the OS so that it treats this particular port as another drive.


http://www.cling.gu.se/~cl3polof/serslave/


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Tue Sep 20, 2005 3:04 am 
Offline

Joined: Sat Jan 04, 2003 10:03 pm
Posts: 1706
bogax wrote:
Quote:
My idea: most computers I know off have a RS-232 port. We can program the OS so that it treats this particular port as another drive.


http://www.cling.gu.se/~cl3polof/serslave/


WOW -- That multi-color interlace picture they have on that page is phenominal. Very cool -- I wish that existed back when I had my C64. ;)


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Tue Sep 20, 2005 4:22 pm 
Offline

Joined: Sat Jan 04, 2003 10:03 pm
Posts: 1706
In light of the fact that a 6502 system contains zero memory protection features, and in light of the fact that there is an increasing trend towards multitasking operating systems for 6502 and 65816 systems, it seems appropriate to reference this document at this time:

http://www.stanford.edu/~candea/papers/ ... honly.html

Very interesting read. They discuss the issue from a web/internet perspective, but the general concepts apply universally. This paper might give you some ideas.


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

All times are UTC


Who is online

Users browsing this forum: Google [Bot] and 2 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: