Jump to content

apersson850

Members
  • Content Count

    1,063
  • Joined

  • Last visited

Everything posted by apersson850

  1. This is not generally true. Byte operations like Add byte can use the addresses 123 and 345, in an instruction like AB @123,@345, and actually add the two odd-addressed bytes together, and store the result at 345. So odd-byte addressing is possible. However, when using registers (those that aren't, but pretend to be), in an instruction like AB R2,R4, you'll add the most significant byte of R2 with the most significant byte of R4, and store the result "to the left" in R4. If we assume the context that LWPI >1000 which defines the virtual R0 to be at >1000 in memory, preceeded the instruction AB R2,R4 then this is completely equivalent to AB @>1004,@>1008 The only difference is that the register only instruction requires one word, the other three. Since the first is shorter and has fewer memory accesses, it's also faster. This means that if you want to add the two least significant bytes of R2 and R4, you can use AB @>1005,@>1009 The register file in memory makes it easy to use a separate register set momentarily, by LWPI NewWP, do whatever, then LWPI OldWP and you continue with your old values in the registers. The 9900 doesn't have a predefined stack register. Return from subroutines called by BL @Sub are returned from by executing B *R11. The return address is stored in R11, so by branching indirectly to that, you return to after your Branch and Link instruction. As a consequence, you can't call another subroutine from the first, unless you take care to save the return address on the first level yourself. Either you implement a stack, or save it in some handy location. But you can do a more elaborate BLWP @SepWSSub, to call a subroutine with a separate workspace. The Branch and Link with Workspace Pointer branches via a vector. This vector consists of two words. The address of the new workspace followed by the address of the code to run. In the new workspace, the BLWP instruction will automatically store the old WP in R13, the return address (old PC) in R14 and the status register, as it was prior to making the call, in R15. Hence this will give you a subroutine that has its own workspace, but can acess data in the caller's registers via R13, or data stored after the call instruction via R14. To access the caller's R5, and store this in the subroutine's R5, you'd execute MOV @10(R13),R5 since the caller's R5 is ten bytes down in his workspace. To fetch in-line data after the call to your R6, you'd use MOV *R14+,R6 This will move a word located right after the BLWP instruction to R6, and also increment R14 by two, so that it points to the actual code following the call instruction. When an interrupt is signalled, an implicit BLWP, via a vector in a pre-defined address in memory, occurs. This means that without explicitly saving anything on a stack, the interrupt starts running with a fresh set of registers, as well as with the previous status word handy, so you can return to the previously executing code and restore the context you had completely. A return is done with the RTWP instruction in both cases. RTWP uses the data in R13, R14 and R15 to restore the registers WP, PC and ST in the CPU. As explained above, the CRU is Texas Instruments version of I/O addressing. You install hardware, wired to look at the CRU command signal and decode the address given, so that you can set or read a bit from this hardware. The hardware can be anything: Latches, LSI chips with pre-defined functions, like UART, general timer/IO-chip, floppy disc controllers etc. Since it's bit-serial, you can easily define hardware ports of odd sizes. Two eight-bit latches can make three ports, five, seven and four bits wide. Many microprocessors would require three eight-bit latches to implement that efficiently, where three, one and four bits were unused. The 9900 concept is more about flexibility than utmost speed. Many instructions allow a general address, which can be either directly to a register, indirectly via a register, indirect with auto-increment, indexed or symbolic. There are no restrictions on which of these you use in that case.
  2. Earlier versions, like UCSD p-system II (similar to Apple Pascal) didn't, but version IV does support a "true heap", i.e. a heap where you can allocate and reclaim space, regardless of which order you do it in. Earlier p-system versions worked only with mark and release, where you could put a mark on the heap, then issue any number of new and finally get rid of them by release, which wound you back to the corresponding mark. But version IV will allow you to do new(a), new(b), new(c) in a row, then dispose(a) and actually free the space used by a, but still keep b and c. This does of course cost more complexity and time for these operations, but is in line with the p-systems philosphy of prioritizing being able to do as much as possible with a small memory footprint.
  3. HEAPOPS are Heap Operations, i.e. the operating system procedures which manage the heap. Like in many other systems, the p-system has two variable storage areas, the stack and the heap. The stack is used in the conventional manner, i.e. things are always pushed on the top of the stack and also popped off the top of the stack. The heap is a memory area where sections are allocated and released in any order. The stack is used to allocate return links, data to be processed, environment records (local variables) and such stuff. Each process (independently executing program in a multi-programmed environment) has its own stack. You allocate one when you start the process. Dynamic variables are allocated on the heap. They can be used for anything, but typical uses are leaves of trees of unknown (at programming time) size, buffers and other structures, where you don't know in advance what you need, or it makes sense to dispose the structures after use, so you don't occupy large areas of memory with data space that's idle. If several processes use the heap to allocate and dispose variables, it does take that the heap protects itself against being interrupted where that can't be allowed. It seems it doesn't. Many other things did work well, though. This is different compared to many versions of Forth, where typically two stacks are used instead. One data stack and one return stack. The way Pascal works, when you create a "word" (a function or procedure in Pascal), you also create the local variables the "word" needs. When the "word" ends, you pop all these local variables, pop the return address, push the results from the "word" (if it's a function) on the stack and return. So no separate return stack is needed.
  4. I tried to convert the UCSD p-system to inlude pre-emptive multitasking. It kind of works, but there's something in HEAPOPS that goes wrong. Without dynamic variables, multitasking isn't much worth, so I gave up there. It has occurred to me at later dates that I could probably make another attempt, where I instead allow the use of the ATTACH intrinsic. When it's properly implemented, it allows linkage of hardware interrupts to semaphores, which in turn implies that you can let a Pascal process go due to an interrupt. it will still be a system with a volutary task switch, but you can have a semaphore being signalled by an external event. Such an approach would probably allow the HEAPOPS to work properly, as it wouldn't be interrupted unless it wanted to itself. Of course you are smart. It's just that you aren't alone... Anyway, using RTWP to call a process is a pretty given thing in the TMS 9900 multitasking world.
  5. I don't know if it's not working properly. As soon as I realized that the type command is missing, I lost interest in it. You can write Pascal programs that don't use dynamic memory, or you get around that by having them imlicitly created and disposed on the stack instead, in local variable environment records, but using Pascal without type is like a car without any engine. I never saw execution speed of UCSD Pascal as a big problem. With the comparatively small memory of the TI 99/4A, I considered its ability to do a lot in a small memory space more valuable. It's also pretty simple to write assembly support for Pascal, both due to how the PME works and the features in the assembler, allowing relatively easy linkage to most data structures you have.
  6. That works fine. I've done the same thing, when doing multi-tasking things in assembly. I've actually posted that code here once, in some thread. When I forced a task switch in the UCSD-system, I simply called the operating system's task switch routine. Do you use pre-emptive task switching in Multi-task Forth, or is it voluntary?
  7. The PME (the P-Machine Emulator, the program that interprets p-code for the UCSD p-code card) is also executing a stack-centered byte-code. The inner interpreter for the PME is written so that it can handle p-code stored in VDP RAM, normal RAM or GROM. The p-code card contains 48 K of GROM, which holds quite a lot of p-code and some data. The inner interpreter is moved to RAM PAD at >8300 when the system executes. There are different versions of it, to handle exactly the issue described above. Note that jumps must be handled differently, since a jump when the code is in RAM simply consists of reloading the instruction pointer, but a jump when the code is in GROM, or VDP RAM, consists of reloading the read address to the memory device port. And that reloading is different for VDP RAM and GROM.
  8. That's one of the big advantages with my internal memory expansion. I can replace the internal ROM chips (8 KBytes) with whatever I like.
  9. Not necessarily. The concept of context switch usually also goes with the concept of private stacks. When you have a stack, you don't need BLWP to be able to nest a lot of subroutine calls. Just push the links. So when you actually do a BLWP, it's either because you just want to do something complex enough to motivate using a private workspace (you can easily copy the caller's stack pointer, if you want to), or you want to enter a complex environment, where you want to use your own stack. This could be an interrupt thing, or a process called by a scheduler in a multiprogrammed system. I've used both these concepts on the 99, so they are perfectly doable.
  10. There's no support for data structures (type) and no support for dynamic variables (new). These are the two essential things that makes Pascal something much better than conventional BASIC. Hence the Turbo Pasc'99 compiler can't be considered anything but meaningless. You can just as well use a small C compiler. The only Pascal worth using on the 99 is the UCSD Pascal, with the UCSD p-system. That, on the other hand, is equivalent in functionality to Borland's Turbo Pascal version 4.
  11. Print a prompt for the user to enter the equation to plot as line number 10, then give the command RUN. After that, exit the program and just wait until it's RUN again.
  12. I've translated the manual to English. It should be in some repository here. But the language isn't uesful at all.
  13. If you don't have problems you don't need to clean it yet. I've cleaned mine when there was a problem reading/writing, which so far has happened exactly zero times. But I've only been using them for 40 years.
  14. The side port is slightly different compared to the bus in the PEB, but not suitable for this modification, no.
  15. Putting it in the expansion box doesn't work. You'll not get the 16 bit wide memory bus, so you don't get the speed advantage. Also it's not doable at all, since my design sits inside the console's memory decoding logic. It has the ability to hijack the console's access to everything, including operating system ROM, cartridge memory - anything. You can even overlay memory across the internal RAM PAD, sound chip, VDP chip, speech etc. It will kill access to all these functions, but you can use that 8 K bank as a buffer for something, when you don't need to update the screen, play sounds or anything else like that. So the advantage is that you can have contiguous RAM across 64 KBytes, provided the data/code you have at certain locations doesn't have to be available all the time. You have to turn some of it off to access disk drives, video display etc. But you can copy the console ROM into RAM, then modify interrupt vectors, the GPL interpreter - well, everything. I have a program which makes a RAMdisk of these 64 K, plus the memory in a GRAM Kracker/Maximem module. You could make a game that has an elaborate AI, all in assembly, which can run in, say, 32 K of fast RAM, then with a single CRU instruction, you disable that memory and get the standard console back. But the content of this 32 K is still there, so the next time it's the computer's turn, you execute one CRU instruction and have it all back again. I'm not saying this just because it's my own design, but it's actually the most versatile memory expansion scheme I've seen for the 99/4A, which also allows a 110% performance upgrade (if you run both workspace and code in normal expansion RAM, compared to both in fast memory). Some other designs are close, but they didn't have the imagination to make the bank switching software controlled, but use manual switches instead. Or they have much more memory, but access it only through a porthole like 4 KBytes wide or so. The big disadvantage with my design is that it's tricky to install. Just imagine if TI had done that from the beginning...
  16. Yes, much more memory. But not 16 bit wide and not designed in the 1980's, so it's a bit different.
  17. I didn't have any easy way of making a PCB at that time, so everything is piggy-backed on exisiting circuits. Picture of computer's board Wiring diagram Block schematics Slight modification to the design took place after the diagram was done. But this is way off topic in this thread.
  18. Well, I added 64 KBytes of static RAM, covering all the address range of the TMS 9900. By default, only 2000H-3FFFH and A000H-FFFFH is enabled. By using CRU bits (base address 400H), I can enable the remaining RAM, 8 KBytes at a time. I can also disable the RAM at the normal memory expansion addresses, which will allow a standard memory expansion, like a card in the PEB, to become visible. So it's possible to get full 64 K contiguous RAM, as well as use either the fast internal 32 K RAM or the standard speed 32 K RAM, as you like. This gives a total of 96 K RAM available, under software control.
  19. I really like the 64 KBytes internal 16-bit wide RAM I put into my console. It's relieving to not have to worry where code, and workspace, is located, as all is equally fast.
  20. In Swedish: "En fem-femma". Translates to "A five-fiver". This comes from the 1864 year criminal act, where you could avoid punishment if you were declared insane acoording to the definitions in the firth chaper of the fifth paragraph. That legislation is now succeeded by the 1965 criminal act. But although the expression has lost its legal value, it's still sometimes said in a derogatory meaning.
  21. The only chip I've ever had to replace in my original TI 99/4A is the PSI, the TMS 9901. My console has seen a lot of running hours, for sure.
  22. I don't think I have Mechatronic Extended BASIC II Plus, so that will not happen. I never went into simulating the 99/4A. If I'm going to use some obsolete computer, it will be the real thing. And no, it's not good to discuss a project piecemeal. You have to have the full plan first, before you start implementing the parts. Otherwise you risk completing a first part in a way that's awkward for some further step.
  23. Well, you came up with the idea, so it's rather you who are the project manager. I'm giving suggestions to how to bring this project any further now. I don't intend to take on any project management role. As you've stated all the time, it's supposed to be a "together project". Again, the next thing to consider is how to get the function(s) into the program.
  24. Not that I've used RXB, but from what I've heard of it, you can use The missing link. But RXB itself doesn't provide for bitmapped graphics. There may be something else in RXB that's beneficiary for this project, but until we know what else to do, you can just as well use the normal Extended BASIC.
  25. Since I'm a professional in this field, I have a realistic mindset. Those who have no idea sometimes consider that negative. I was about to comment on the plotting part, but senior_falcon beat me to it. That also Forth (all versions, but lets stay with fbForth) have the ability to switch to bitmap mode is well known, so the prerequisites are there. Pascal doesn't support bitmap, as it's delivered, but I made it possible. Perhaps somebody else too, but I've never heard about it. It doesn't matter either; it's at least possible with what I did. That there would be an interest in doing all the extra work required to implement this in assembly only - well, I don't think so. Going that way it will never be ready. So, to bring this project any further, the next cow it is. What's the best way to get the function to plot into the program? The reasoning above leads us to three possible languages/operating environments to use: Extended BASIC supported by The missing link, fbForth or UCSD Pascal.
×
×
  • Create New...