Jump to content
IGNORED

Pascal on the 99/4A


apersson850

Recommended Posts

Anyone here know why this simple program is not working? It's supposed to read a text file character by character, echo the text to the screen and write it back to another text file. Everything is working except that the target file remains empty. No errors are issued. Puzzling...

{ character copy primitive }
program copyprog;
const
   ENDFILE = -1;
   NEWLINE = 10;  { ASCII value }
type
   character = -1..127; { ASCII plus ENDFILE }
var
   f,o : interactive;

{ getc -- get one character from standard input }
function getc (var c : character) : character;
var
   ch : char;
begin
   if (eof(f)) then
      c := ENDFILE
   else if (eoln(f)) then begin
      readln(f);
      c := NEWLINE
   end
   else begin
      read(f, ch);
      c := ord(ch)
   end;
   getc := c
end;

{ putc -- put one character on standard output }
procedure putc (c : character);
begin
   if (c = NEWLINE) then begin
      writeln;
      writeln(o)
   end
   else
      write(chr(c));
      write(o, chr(c))
end;

{ copy -- copy input to output }
procedure copy;
var
   c : character;
begin
   while ( getc(c) <> ENDFILE ) do
      putc(c)
end;

begin   { main program }
   reset(f, '#5:test.text');
   rewrite(o, '#5:testout.text');
   copy;
   close(f);
   close(o) 
end.

 

Link to comment
Share on other sites

Puh ... I'm a little bit spoiled by Delphi and Lazarus and never did Pascal on the TI. Though pascal had become my native digital tongue somehow in the early 90's and I never went beyond. 

 

It looks good at first sight.

 

My thoughts in random order:

  • Is the file testout.text created but empty?
  • close() should call flush() .. or should this be done manually in TI Pascal?
  • try a writeln(o,'this is a test') instead of the copy command ... is it written to disk?
  • I have never seen "interactive" as a type. Is it comparable with standard Pascal "TEXT" ? Or "FILE of BYTE" or what? I did not find a good explanation in the UCSD Pascal Docs.

Why do you need the extra handling of NEWLINE? Isn't >0A a character like all others and could be handled as a normal, displayable char?

 

PS: Found a good definition of 'interactive' in the Apple manual.  It looks good for screen and keyboard, but not for files on disks ... is there a special reason to use it instead of TEXT?

 

 

Edited by SteveB
PS added
  • Like 1
Link to comment
Share on other sites

20 minutes ago, SteveB said:

My thoughts in random order:

  • Is the file testout.text created but empty?
  • close() should call flush() .. or should this be done manually in TI Pascal?
  • try a writeln(o,'this is a test') instead of the copy command ... is it written to disk?
  • I have never seen "interactive" as a type. Is it comparable with standard Pascal "TEXT" ? Or "FILE of BYTE" or what? I did not find a good explanation in the UCSD Pascal Docs.

Why do you need the extra handling of NEWLINE? Isn't >0A a character like all others and could be handled as a normal, displayable char?

 

PS: Found a good definition of 'interactive' in the Apple manual.  It looks good for screen and keyboard, but not for files on disks ... is there a special reason to use it instead of TEXT?

 

 

  • testout.text is a pre-existing empty text file
  • There is no flush() with UCSD Pascal. Should be automatically handled by the close command
  • writeln(o, 'this is a test') does not write anything to disk either
  • The reason I use interactive instead of text is because it is the default for UCSD Pascal. If I was to use text, then I would have to replace read with the pair ch := f^ and get(f), and replace write with o^ := c and put(o). There is a good explanation of why that is on pages 22-24 of the compiler manual. I tried it both ways and the result is the same.
  • Using NEWLINE is simply for clarity rather than use decimal 10. 

A bit of a background about all this: I am currently reading an excellent book from 1981 called "Software Tools in Pascal" by Kernighan and Plauger, pointed out by FarmerPotato. It teaches us proper Pascal program structure and design, as well as fleshes out a series of tools for source text manipulation. Great read, if a bit geeky 😁

 

Still puzzled...

  • Like 4
Link to comment
Share on other sites

Yes that's it! I did not realize that the close statement took options under UCSD Pascal. It's all detailed on page 52 of the compiler manual. That said it seems to me that the default behavior should have been to flush the write buffer to the file instead of requiring a special option for that...

Thanks!

  • Like 2
Link to comment
Share on other sites

12 hours ago, Vorticon said:

Yes that's it! I did not realize that the close statement took options under UCSD Pascal. It's all detailed on page 52 of the compiler manual. That said it seems to me that the default behavior should have been to flush the write buffer to the file instead of requiring a special option for that...

Thanks!

I agree. That seems strange to not **flush on close(). 

Maybe @apersson850 has an explanation or some deeper insights why it is this way.

 

 

**Not to be confused with the rule of the water closet: always close before flushing. :) 

  • Like 4
  • Haha 1
Link to comment
Share on other sites

  • 7 months later...

There have been several posts over the last years about making it possible to run the p-system without the p-code card. Or rather with a replacement. Some insight in the memory use of the p-system could be handy, should anyone ever attempt it again.

The p-system has quite a lot of features you don't get in the BASIC environment, for example. Due to this, it's also more memory hungry. A p-system IV.0 can't really run on a machine with as little as 32 K of RAM (the rest is video RAM). To make it possible, the p-system on the 99/4A uses some tricks.

One of the most important is allowing p-code to run from three different types of memory: CPU RAM (the normal one), VDP RAM (video) and GROM (TI's special memory mapped ROM circuits).

 

Usage of memory:

CPU RAM 8 kbyte part

Screen buffer for the 80 column screen.

Jump table for the PME.

Code for things that can't run from the p-code card, like interrupt and IO-handling.

 

CPU RAM PAD (256 bytes)

PME inner interpreter.

System related things, like FAC and similar.

Workspaces.

 

CPU RAM 24 kbyte part

Heap.

Secondary code pool.

Stack.

 

VDP RAM.

16 kbytes accessed via the VDP.

Screen content.

Primary code pool.

Disk buffers.

 

P-code card ROM

12 kbyte in the DSR space.

PME.

BIOS.

 

P-code card GROM

48 kbyte read only on the card, mapped in the DSR space.

Assembly code repository for things loaded during startup and then to the RAM in the lower expansion area.

The operating system's disk unit OS: (a GROM-disk).

  • Like 6
  • Thanks 1
Link to comment
Share on other sites

Hi, @apersson850.  It has been a long time.  

 

I am so glad to see your post.  I have naïve questions, as you have come to expect from me.

 

"Or rather with a replacement."  

 

p-code is interpreted, so there must be an interpreter in ROM for compiled Pascal code, as well as to act as the system OS (? maybe not, maybe executing p-code is just a switchable mode of a flexible OS?). Do you mean p-code embedded in ROM on a cartridge?  Or some other form of ROM injection?  Is there a clear path forward from the 99/8 architecture that incorporated p-system IV in the form of motherboard ROMs?

 

I suppose a cartridge is an advantage over having a PEB, but availability of ROMs is one of several problems to solve.  Pascal was resource intensive for its day.  On the TI it required a PEB and memory expansion, as you point out.

 

(Sidebar: I'd argue that resource intensity of Pascal carried forward in the successor language Java. The JVM footprint, the #includes with the standard compile... by 2012 a simple service written in Java had a gig-plus footprint. Admittedly most of these were language defaults of convenience, which can be overridden.  Still, it can be argued that Java resource bloat was no small contributor to the success of Python, but ... ok, sidebar, I'll stop, you haven't missed this dribble.)

 

"uses some tricks"  

 

Not uncommonly on the TI and similar systems of yore, we ran out of core and we had to write memory swap routines. We swapped to disk because that was where the storage was.  

 

It was a humbling moment in the early 80s when I told my dad of all of these memory expansion techniques I'd figured out for the TI (reality check: they were just crude disk I/O) when he told me of the stuff he did on an IBM 1401 and later a first generation System/360 to accomplish the same, and more.  That's great, kid.  Let me tell you how the world works.

 

In your opinion, is the Pascal memory management sufficiently optimized or is there a memory management optimization worth embedding in Pascal code on the 99/4 and /4A?  I believe your post describes what makes a p-system ROM a good citizen, but is there a "what makes a Pascal program a model citizen"?  

 

Again, my questions are just naïve and interpretations of what you posted, Anders.  They may not be worth answering.  But your post got me thinking just the same.

 

Best regards,

 


R.
 

Link to comment
Share on other sites

The p-system is a system in layers.

At the bottom, there are hardware specific services, like for the keyboard, screen, disk IO, interrupt services and similar. These are written in 9900 assembly language.

At the next level, there is the PME, which interprets p-code. This is written in 9900 assembly language and runs mainly from the p-code card's ROM chips. Some of it is in 8 K RAM and the innner part in RAM PAD at 8300H (for speed reasons). The PME can execute p-code from all sorts of memory, CPU RAM, VDP RAM or GROM.

Then there is the main operating system, which is mainly written in Pascal and compiled to p-code. The operating system is stored in GROM chips on the p-code card. Some parts stored there are 9900 assembly code. It can't be executed from GROM, but is moved to 8 K RAM for execution. So the GROM is in that case just a repository.

Then there are various external parts of the operating system, like the Filer, which is stored on disk and read into RAM to execute. Code is running from one of the code pools. The main code pool is in VDP RAM, to avoid occupuing the secondary code pool more than necessary. The second code pool is in 24 K RAM, where it competes with the heap and stack for space. So more code there implies less space for variables.

 

The only advantage of not having the p-code card is that you don't need a PEB then, providing you have other ways of handling expansion RAM and disk storage. And that the p-code cards are in somewhat short supply. When TI implemented it, the resources required wouldn't fit in a cartridge and you needed the PEB anyway, so it wasn't too big a deal.

 

The memory management allows for writing software that can be segmented, so that not all segments need to be in memory at the same time for the program to work. Typically you have one segment that's loaded all the time (the main program), but you can write an input routine in one segment, a printout routine in another segment, a data manipulation and storage handler in a third. Since you neither input, store or print at the same time, the system can load what's needed when it's needed, and also discard a non-used segment if the space it occupies is needed for something else.

 

This applies to code. You can allocate and dispose data areas as you need, but they have to fit in the 24 K RAM, together with the stack, other data and any code that needs to run there. From this, it's obvious that if you can keep segments small enough so that the calling segment and called segment both fits in the primary code pool (VDP RAM), you have more space available for data.

In my opinion, this is good enough for a small machine like the 99/4A. Adding more features requires more support code, which will use more of that memory we try to save for our own use.

  • Like 3
Link to comment
Share on other sites

The p-system has pointers to where the main code pool starts and ends.

When I implemented bit-mapped graphis with Pascal I changed the pointer. This means that many more programs have to run from the secondary code pool, as the remaining part of the primary one is pretty small. But as long as they fit in there, the system works the same as always. Well, not for screen output, of course, but the rest.

There's a way to force a program to load in the secondary pool, no matter what, but it's better to just let the system check the remaining space in the small pool there is left and determine if it's enough or not.

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

I'm not saying it would be easy, but the Geneve does have the source code for the PSYSTEM.  I am not sure how easy it would be to port over to the TI-99/4A, but with a F18a and a SAMS, there may be a possibility.  I don't know if anyone has ever explored that option/opportunity.

 

Just throwing it out there.

  • Like 2
Link to comment
Share on other sites

7 hours ago, apersson850 said:

The p-system has pointers to where the main code pool starts and ends.

When I implemented bit-mapped graphis with Pascal I changed the pointer. This means that many more programs have to run from the secondary code pool, as the remaining part of the primary one is pretty small. But as long as they fit in there, the system works the same as always. Well, not for screen output, of course, but the rest.

There's a way to force a program to load in the secondary pool, no matter what, but it's better to just let the system check the remaining space in the small pool there is left and determine if it's enough or not.

Is there documentation somewhere on these pointers?

Link to comment
Share on other sites

14 hours ago, 9640News said:

I'm not saying it would be easy, but the Geneve does have the source code for the PSYSTEM.  I am not sure how easy it would be to port over to the TI-99/4A, but with a F18a and a SAMS, there may be a possibility.  I don't know if anyone has ever explored that option/opportunity.

I took a quick look. It doesn't seem to be the same version of the p-system that's running on the Geneve as on the 99/4A. There are also differences like that ATTACH is implemented, so the interrupt structure is different and that's exploited in the Geneve.

 

Some day when I have more time than I know what to do with it all, I'll make a deep dive into the source code for the Geneve...

  • Like 1
Link to comment
Share on other sites

15 hours ago, apersson850 said:

For the primary code pool they are at 2780H and 2782H. You can find them here.

Looking at the document, it seems I've not figured out where they are for the secondary code pool. I probably didn't need them.

Thanks! So basically I can just point 2780H to the first free VDP address after setting up the bitmap space and 2782H to last free address and the OS should handle it from there as far as the code pools are concerned?

Link to comment
Share on other sites

When I reserve space for bitmap, I just check that the top memory pointer isn't smaller than what the bottom pointer needs to be. If not, there's space available for bitmap.

Here is the code to do it.

 

program bit_map_reserve;
  (* Utility used for pre-reserving space for bit-map mode programs *)
  (* A-DATA 860604 *)

uses
  screenops;
  
var
  prline :sc_long_string;
  ret_set :sc_chset;
  ch :char;


procedure interpreter(ch :char);
  (* Command line interpreter *)
  
  const
    intmem = 10112;       (* Interpreters VDP memory pointer *)
    topmem = 10114;       (* Top VDP memory pointer *)
    newint = 14360;       (* New intmem value *)
    stdint =  3576;       (* Standard intmem value *)
  
  type
    dual = record
      case boolean of
        true :(int :integer);
        false:(ptr :^integer);
    end; (* dual *)
  
  
  procedure poke(addr,value :integer);
  
  var
    window :dual;
    
  begin
    window.int := addr;
    window.ptr^ := value;
  end; (* poke *)
  
  
  function peek(addr :integer):integer;
  
  var
    window :dual;
  
  begin
    window.int := addr;
    peek := window.ptr^;
  end; (* peek *)
  
    
  procedure clearline;
    (* Clears common prompt line *)
  
  begin
    sc_gotoxy(0,1);
    sc_clrcurline;
  end; (* clearline *)
  
  
  procedure allocate;
    (* Reserves space for bit-map mode *)
  
  begin
    clearline;
    if peek(topmem)<newint then
      writeln('Reservation impossible')
    else
    begin
      poke(intmem,newint);
      writeln('Space reserved for bit-map');
    end;
  end; (* Allocate *)
  
  
  procedure deallocate;
    (* Releases space reserved for bit-map *)
  
  begin
    clearline;
    poke(intmem,stdint);
    writeln('Bit-map space released');
  end; (* deallocate *)
  
  
  procedure show;
    (* Displays current VDP RAM space *)
  
  begin
    clearline;
    writeln('Current VDP space is ',peek(topmem)-peek(intmem),' bytes');
  end; (* show *)
  
  
begin (* interpreter *)
  case ch of
    'A' :allocate;
    'D' :deallocate;
    'S' :show;
  end; (* case *)
end; (* interpreter *)


begin (* main *)
  prline := 'Bitreserve: A(lloc,D(ealloc,S(how,Q(uit';
  ret_set := ['A','D','S','Q'];
  repeat
    ch := sc_prompt(prline,-1,0,0,0,ret_set,false,',');
    interpreter(ch);
  until ch='Q';
end.

 

By reserving space for bitmap prior to loading your program that uses bitmap, you don't fall into the trap that the program you have loaded to use bitmap already have occupied the space you need for bitmap.

I think I did set the language type for the program bitreserve to M_9900 instead of pseudo, to make sure it's not itself in VDP RAM.

  • Like 2
  • Thanks 1
Link to comment
Share on other sites

Thank you! Do you happen to have the source of the sc_prompt procedure? 

So when you reassign the pointers, are the code pools immediately relocated? I assume that the change is persistent until the next system reset?

Apologies for all the questions, but I have a project in mind that I'd like to implement on the TI. I recently wrote a Boids flocking simulation in Pascal on the TRS-80 Model 4P and it will require bitmap access for a proper display on the TI. The source itself is pretty much standard Pascal and should port quite easily.

 

  • Like 1
Link to comment
Share on other sites

No, I don't have the source for sc_prompt. But that procedure is hosted in unit screenops, which is delivered with the system.

Yes, when the pointers are updated, the next request to the code loader to load code into the code pool will take the new values into account. So the probability that the code ends up in the secondary code pool increases dramatically. I think it stays until the next reset, or if you use the program bitreserve to give it back to the system.

 

Well, feel free to use the whole turtlegraphics unit if you like. It's not optimized all the way, and some things aren't fully implemented, but it's useful and works (as far as I know). Look at whtech/programming/pascal/turtle.*. There are a few files, including the one I posted above.

OK, looking at it I realize that many of the programs that demonstrate the use of turtlegraphics require my own unit extrascreen too. It's used for keyboard input. Normally you don't want to show an entered key on the screen when bitmap graphics is displayed. My unit extrascreen allows for reading keys without any screen echo. It also allows for doing this even if they keyboard buffer isn't where it normally is, and that's the case when bitmap mode is used. The p-system supports buffered keyboard input, and normally that buffer is in VDP RAM that's needed for bitmap mode. So I have to move it, but that I can handle and so can the system.

Edited by apersson850
  • Like 2
  • Thanks 1
Link to comment
Share on other sites

On 8/22/2020 at 1:43 PM, ralphb said:

Here is a DS/DD disk image with all individual P system disks combined.  If your controller can handle DS/DD, the disk makes it a lot easier to work with the P system.

 

Thanks to Anders for helping me create this disk!

pcode.dsk 360 kB · 106 downloads

I'm new to disks/PEB on a 99 (back in the day only had a tape drive & synth)

 

Is it too much to hope that if I upload this dsk file to my TIPI I can just copy the PASCAL file it extracts to a normally formatted disk and it will work with the p-code card please?

 

Many thanks

 

 

Link to comment
Share on other sites

We were discussing floating point in the CORTEX BASIC thread.  I thought of the math library that I had seen. 

It's math.src from Microprocessor Pascal for TM990/101 microcomputer.  I thought it may be of interest here.

 

The formulas are attributed to:

Computer Approximations, John F. Hart, et.al., John Wiley & Sons, 1968. 

 

ARCTAN(X)
SIN(X)
COS(X)
EXP(X)
LN(X)
SQRT(X)

 

Pascal source (also see attached).  I apologize for any garbage characters - the fpyfile util for sim990 left 2-byte record#s in the text.

 

Spoiler

 

 

math.src

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

3 hours ago, Atari2600PAL said:

Is it too much to hope that if I upload this dsk file to my TIPI I can just copy the PASCAL file it extracts to a normally formatted disk and it will work with the p-code card please?

No, it's not too much. What's imperative is that the PASCAL file is not only transferred, but that it ends up in exactly the same sectors as it originally occupied on the disk it was copied from. Which it normally does, if you copy it to an empty disk.

 

This is due to the fact that the PASCAL file is never used by the p-system. It's there just as a dummy file, to mark the diskette as fully used. The p-system instead accesses certain sectors on the disk, where it has its own file system with directory and files.

Link to comment
Share on other sites

Join the conversation

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

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

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

×   Your previous content has been restored.   Clear editor

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

Loading...
×
×
  • Create New...