Jump to content
IGNORED

Pascal on the 99/4A


apersson850

Recommended Posts

Inspired by @TheBF, I went ahead and created a clock unit which can display various formats of date and time anywhere on the text screen. I can't demo it right now as I am on my laptop and not on real hardware but it should work just fine.

Spoiler
unit clockutil;
{displays various formats of date/time}

interface

procedure stamp(x, y : integer);
procedure long_date(x, y : integer);
procedure date(x, y : integer);
procedure dmy(x, y : integer);
procedure mdy(x, y : integer);
procedure long_time(x, y : integer);
procedure time(x, y : integer);

implementation

procedure getdow(dow : integer; var downame : string);
{converts numeric dow to named dow}
{sunday = 1}

var
 dowstr : array[1..7] of string;
 
begin
 dowstr[1] := 'sunday';
 dowstr[2] := 'monday';
 dowstr[3] := 'tuesday';
 dowstr[4] := 'wednesday';
 dowstr[5] := 'thursday';
 dowstr[6] := 'friday';
 dowstr[7] := 'saturday';
 
 downame := dowstr[dow];
end; (* getdow *)

procedure getmonth(month : integer; var monthname : string);
{convert numeric month to named month}

var
 monthstr : array[1..12] of string;
 
begin
 monthstr[1] := 'january';
 monthstr[2] := 'february';
 monthstr[3] := 'march';
 monthstr[4] := 'april';
 monthstr[5] := 'may';
 monthstr[6] := 'june';
 monthstr[7] := 'july';
 monthstr[8] := 'august';
 monthstr[9] := 'september';
 monthstr[10] := 'october';
 monthstr[11] := 'november';
 monthstr[12] := 'december';

 monthname := monthstr[month];
end; (* getmonth *)

procedure cdate(var day, dow, month, year : integer); external;
procedure ctime(var sec, min, hr : integer); external;

procedure stamp;
{format: short-dow, short-month day, year, hr:min:sec}

var
 dow, month, day, year, sec, min, hr : integer;
 dowstr, monthstr : string;

begin
 ctime(sec, min, hr);
 cdate(day, dow, month, year);
 getdow(dow, dowstr);
 dowstr := copy(dowstr, 0, 3);
 getmonth(month, monthstr);
 monthstr :=copy(monthstr, 0, 3);
 gotoxy(x, y);
 writeln(dowstr,', ',monthstr,' ',day,', ',year,' ', hr,':',min,':',sec);
end; (* stamp *)

procedure long_date;
{format: long-dow, long-month day, year}

var
 dow, day, month, year : integer;
 dowstr, monthstr : string;

begin
 cdate(day, dow, month, year);
 getdow(dow, dowstr);
 getmonth(month, monthstr);
 gotoxy(x, y);
 writeln(dowstr,', ',monthstr,' ',day,', ',year);
end; (* long_date *)

procedure date;
{format: short-month day, year}

var
 dow, day, month, year : integer;
 monthstr : string;
 
begin
 cdate(day, dow, month, year);
 getmonth(month, monthstr);
 monthstr := copy(monthstr, 0, 3);
 gotoxy(x, y);
 writeln(monthstr,' ',day,', ',year);
end; (* date *)

procedure dmy;
{format: day/num-month/short-year}

var
 dow, day, month, year : integer;
 
begin
 cdate(day, dow, month, year);
 year := year - 2000;
 gotoxy(x, y);
 writeln(day,'/',month,'/',year);
end; (* dmy *)

procedure mdy;
{format: mum-month/day/short-year}

var
 dow, day, month, year : integer;
 
begin
 cdate(day, dow, month, year);
 year := year - 2000;
 gotoxy(x, y);
 writeln(month,'/',day,'/',year);
end; (* mdy *)

procedure long_time;
{format: hr:hr min:min sec:sec}

var
 sec, min, hr : integer;
 
begin
 ctime(sec, min, hr);
 gotoxy(x, y);
 writeln('hr:',hr,' min:',min,' sec:',sec);
end; (* long_time *)

procedure time;
{format: hr:min:sec}

var
 sec, min, hr : integer;
 
begin
 ctime(sec, min, hr);
 gotoxy(x, y);
 writeln(hr,':',min,':',sec);
end; (* time *)

end. (* clockutil *)
 

 

 

  • Like 2
Link to comment
Share on other sites

Many years ago I had centre-fold from a magazine on my locker door, that was a red velvet cloth with a Pascal listing spread out on the cloth.

 

I am thinking of that centre-fold when I see your code. 

 

🤣

 

I noticed the confused icon.

 

The implication from the computer magazine (April 1st issue) centre-fold was that Pascal was "beautiful". 

  • Haha 1
  • Confused 1
Link to comment
Share on other sites

I have a program for my real TI 99/4A where it sets the hardware clock chip to generate interrupts and when that happens, it prints the current time in the upper right corner of the screen. Overwriting what may be there, but that doesn't matter with the p-system, since it writes on the physical screen, not the 80 column screen block. So the data that used to be on the screen in that corner is still there, just not visible.

  • Like 3
Link to comment
Share on other sites

1 hour ago, apersson850 said:

I have a program for my real TI 99/4A where it sets the hardware clock chip to generate interrupts and when that happens, it prints the current time in the upper right corner of the screen. Overwriting what may be there, but that doesn't matter with the p-system, since it writes on the physical screen, not the 80 column screen block. So the data that used to be on the screen in that corner is still there, just not visible.

The IDE RTC can actually generate interrupts. How would you detect them in UCSD Pascal?

Link to comment
Share on other sites

On 7/19/2024 at 1:44 AM, Vorticon said:

The IDE RTC can actually generate interrupts. How would you detect them in UCSD Pascal?

The system does that. I just wrote a DSR, which rather was an ISR (Interrupt Service Routine). That ISR read the time from the clock and put it in VDP RAM at a position which ends up in the upper right corner. There's a VDP R1 copy in RAM, so I could check if the screen was 32 or 40 characters wide automatically.

As soon as the clock is set to generate interrupts the P-system will service them.

  • Like 2
Link to comment
Share on other sites

I had some time on my hands and was reading about probabilities, so I created this quick and dirty program to calculate the probability of having a certain number of heads for n consecutive coin tosses. It forced me to deal with the vagaries of precision limitations, real variables formatting, as well as write power and factorial functions. Time well spent :lol:

Spoiler
program cointoss;
{calculates probability of head or tail outcomes (h) in n tosses}

var
 i, n : integer;
 prob, factn, pwrneg2 : real;

function fact(n : integer) : real;
{calculate the factorial of an integer}

var
 f : real;
 
begin
 f := n;
 if n in [0, 1] then
  fact := 1
 else
  begin
   repeat
    n := n - 1;
    f := f * n;
   until n = 1;
   fact := f;
  end;
end; (* fact *)

function pwr(n : real; m : integer) : real;
{calculate n to the power of integer m}

var
 p : real;

begin
 if m = 0 then
  pwr := 1.0
 else
  if m = 1 then
   pwr := n
  else
   begin
    if m < 0 then
     begin
      p := 1.0;
      repeat
       p := p / n;
       m := m + 1;
      until m = 0;
      pwr := p;
     end
    else
     begin
      p := n;
      repeat
       p := p * n;
       m := m - 1;
      until m = 0;
      pwr := p;
     end
   end;
end; (* pwr *)

begin
 page(output);
 gotoxy(0, 2);
 write('number of tosses: ');
 readln(n);
 factn := fact(n);
 pwrneg2 := pwr(2, -n);
 gotoxy(0, 5);
 
 for i := 0 to n do
  begin
   prob := (factn / (fact(i) * fact(n - i))) * pwrneg2;
   write('h: ', i);
   gotoxy(6, i + 5);
   writeln('prob: ', prob:12:8);
  end;
end. (* cointoss *)

 

 

 

  • Like 1
Link to comment
Share on other sites

4 hours ago, apersson850 said:

The system does that. I just wrote a DSR, which rather was an ISR (Interrupt Service Routine). That ISR read the time from the clock and put it in VDP RAM at a position which ends up in the upper right corner. There's a VDP R1 copy in RAM, so I could check if the screen was 32 or 40 characters wide automatically.

As soon as the clock is set to generate interrupts the P-system will service them.

I thoughts interrupts were disabled with the pcode system. I guess I'm wrong then.

Link to comment
Share on other sites

8 hours ago, Vorticon said:

I thoughts interrupts were disabled with the pcode system. I guess I'm wrong then.

Well, yes and no. Hardware interrupts into the CPU are disabled. But the PME implements a virtual processor where the TMS 9900 executes the "microcode" (which is standard assembly instructions) to implement the "assembly language" (which is p-code). The "microcode" (assembly, really) running the PME also senses the interrupt pin to check if there is an interrupt pending. If there is, it's serviced.

 

So yes, the p-system does respond to interrupts, but it does it on a higher logical level than normal. This does of course mean that interrupt latency is larger, since there will be several assembly instructions between each interrtupt serviced. For hardware interrupts is only one assembly instruction. Here it's at least one p-code, and frequently more.

 

So the p-system is clearly not built to react precisely on microsecond things, not even milliseconds, but handle interrupts every 1/10 s it can very well do.

 

On the other hand this approach also means that you can do other things than standard when you get an interrupt request from the VDP, for example. The p-system also handles the full keyboard and thus implements the type-ahead queue, so you can use the keyboard to type in a response to a question even before the question is shown on the screen.

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

8 hours ago, apersson850 said:

Well, yes and no. Hardware interrupts into the CPU are disabled. But the PME implements a virtual processor where the TMS 9900 executes the "microcode" (which is standard assembly instructions) to implement the "assembly language" (which is p-code). The "microcode" (assembly, really) running the PME also senses the interrupt pin to check if there is an interrupt pending. If there is, it's serviced.

 

So yes, the p-system does respond to interrupts, but it does it on a higher logical level than normal. This does of course mean that interrupt latency is larger, since there will be several assembly instructions between each interrtupt serviced. For hardware interrupts is only one assembly instruction. Here it's at least one p-code, and frequently more.

 

So the p-system is clearly not built to react precisely on microsecond things, not even milliseconds, but handle interrupts every 1/10 s it can very well do.

 

On the other hand this approach also means that you can do other things than standard when you get an interrupt request from the VDP, for example. The p-system also handles the full keyboard and thus implements the type-ahead queue, so you can use the keyboard to type in a response to a question even before the question is shown on the screen.

You got my attention. Do you happen to have example code about this? I can see using this for timing functions and such.

  • Like 1
Link to comment
Share on other sites

When a disk pcode disk image is transferred to the TIPI, the latter automatically converts it into a folder containing 2 files: .sector and PASCAL. If anyone in using TIPI disks with the pcode card (I may be the only one but you never know...), the .sector file is the actual disk image which can be opened by pcode tool, NOT the PASCAL file in the same folder. Thanks to @Rhodanaj for figuring this out. This is important if you plan on sharing these images or using them under emulation.

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

Posted (edited)

That's probably the "pseudo-file" called PASCAL in the standard OS that you see too. It's there just to make the whole disk occupied and make it possible to copy it with the Disk Manager module.

 

I had bad luck with some source code for my clock card. I can check, but it could be that I only have the executable files left...

But to use this interrupt function I have requires a DSR with an interrupt service on the clock card. Since I made my own, I designed it to have the clock chip, some CRU config bits and some RAM. I use that memory to load the DSR into.

At boot time, the p-system scans all external cards to see if they have valid interrupt service code. So in my computer, it will store a list of CRU addresses 1300H and 1400H, for the RS232 and clock cards.

The it will examine the pre-listed cards on interrupt to see who's calling for attention.

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

So in theory the system should be able to recognize the IDE card as an interrupt generating card at boot? If that's the case, then what I need to understand is how to service the clock interrupt. I've never worked with interrupts before and I would have loved to see some example assembly code. I'll post that question on the assembly thread.

Link to comment
Share on other sites

7 hours ago, Vorticon said:

So in theory the system should be able to recognize the IDE card as an interrupt generating card at boot? If that's the case, then what I need to understand is how to service the clock interrupt. I've never worked with interrupts before and I would have loved to see some example assembly code. I'll post that question on the assembly thread.

The P code cards use of the word "interrupt" is different than the hardware's concept of the word "interrupt" in that in the P code system it's really the P Code system polling to see if it needs to take over and do something. 

With hardware on the 9900 the CPU actually stops running the code it's doing and does the equivalent of BLWP to a vector in a table of vectors starting at >0000. 

(TI-99 design locks that table in ROM which kind of sucks.  @apersson850 rigged his memory so he can replace the ROM with RAM so he can write the table anyway he wants. I am jealous) 

  • Like 2
Link to comment
Share on other sites

I'll see if I can dig up the source to my clock card's DSR.

 

Yes, if you want to look at the p-system in the traditional way, then you have to do as I explained. View the assembly code in the PME as equivalent to the microcode in a real CPU and the p-code as the assembly code.

Then suddenly you are back on track, since what a real CPU does is that during a suitable microcode cycle (CPU state), it will poll the interrupt input to the chip and see if there's any request. If there is, then the microcode will do what's needed to start running the interrupt service and to make it possible to return to the previous task without losing track of what was going on before the interrupt. The PME instead uses the assembly code to poll the interrupt and stop executing p-code when there is a request. In the 99/4A, the whole interrupt service sequence is written in assembly. Part of it runs in the 8 K RAM part of memory, since servicing interrupts may imply turning the p-code card off, in case the interrupt comes from another card in the box.

 

I've used my console's ability to change the interrupt vectors to implement a multitasking system in assembly. I used the TMS 9901's as a task switch timer. You can't do that unless you can change what's executed on an interrupt.

  • Like 3
Link to comment
Share on other sites

8 hours ago, apersson850 said:

View the assembly code in the PME as equivalent to the microcode in a real CPU and the p-code as the assembly code.

 

Then suddenly you are back on track, since what a real CPU does is that during a suitable microcode cycle (CPU state), it will poll the interrupt input to the chip and see if there's any request. If there is, then the microcode will do what's needed to start running the interrupt service and to make it possible to return to the previous task wi


I'm sure you know this but I found it fascinating that:


9900 Interrupts are granted only after an instruction completes, though they can be sampled (latched) earlier.  Documented in  CPU flowcharts and timing diagrams in the data books. 


Interrupts are NOT granted immediately after a context switch.   At least one instruction executes, so an interrupt handler may do LIMI 0 first to protect a critical section.


And the 9900 instructions are not interruptible while in progress. 
 

In the two 9900 implementations I've studied this year, there is indeed a bit in the micro-instruction word to sample interrupts. I like your choice of  "cycle" for this--much more relatable.  

 

(Two implementations are documented: 990/12 and TM990/1481.   The 9995 and 99105 are partially revealed in patent disclosures.) 

 

  • Like 3
Link to comment
Share on other sites

Finally got around to modifying my SYSTEM.STARTUP file to automatically fetch the date and time and store it on the boot disk (#4). This is based on @apersson850's startup file, with several modifications made obviously to account for my own system. I store the time in sector 3 as 3 separate integers (HR, MIN, SEC) instead of a string since my clock procedures return integers.

The attached boot disk includes the Editor, Filer and Compiler as well as the SYSTEM.STARTUP file which assumes that an IDE card with RTC is present at CRU >1900.

Spoiler
(*$R- *)       (* Turn off range checking *)

PROGRAM INITSTATE;
USES MISC,
{$U COMMANDIO.CODE}
COMMANDIO;

(* This program is a modified version of the MODRS232                   *
 * utility program and sets the PRINTER: to PIO and REMIN/REMOUT:  to   *
 * 2400 8-N-1. Also reads the ide rtc and sets the time.                *
 * Assumes IDE with RTC at cru >1900.                                   *)

   const
      rddata  = -30720;
      rdstat  = -30718;
      wrtdata = -29696;
      wrtaddr = -29694;
      wrtenab =  16384;
      pabtbl  =  10716;  (* hex 29dc *)
      maxlen  =     43;
      DATELOC = 13840; {RAM LOCATION OF SYSTEM DATE}
      DIGIT = '0123456789';


   type
      byte = 0..255;

      DUAL = record
         case boolean of
         true: (int: integer);
         false:(ptr:^integer);
         end;

      BYTEWORD = RECORD
       CASE BOOLEAN OF
       TRUE : (VALUE : INTEGER);
       FALSE : (BYTES : PACKED ARRAY[1..2] OF BYTE);
      END;

      DIRTYPE = RECORD
       TFILL1 : PACKED ARRAY[0..11] OF CHAR;    {SECTOR 3}
       HR : INTEGER;
       MIN : INTEGER;
       SEC : INTEGER;
       TFILL2 : PACKED ARRAY[0..237] OF CHAR;
       FILL1 : PACKED ARRAY[0..19] OF CHAR; (* SECTOR 4, PASCAL DIRECTORY *)
       DLASTBOOT : INTEGER;
       FILL2 : PACKED ARRAY[0..489] OF CHAR; (* SECTORS 4 AND 5 *)
      END;

   var
      cpuaddr: DUAL;
      curlen,period,vdpaddr: integer;
      savevdpaddr: integer;
      ch: char;
      unitno: integer;
      i,j: integer;
      pabname:string[43];
      action, date : string;
      err : boolean;
      WORD : BYTEWORD;
      YEAR, MONTH, DAY, DOW, SEC, MIN, HR : INTEGER;
      MONTHNAME, MSTRING : STRING;
      DIRECTORY : DIRTYPE;
      MONTHSTR : ARRAY[1..12] OF STRING;

PROCEDURE CDATE(VAR DAY, DOW, MONTH, YEAR : INTEGER); EXTERNAL;
PROCEDURE CTIME(VAR SEC, MIN, HR : INTEGER); EXTERNAL;

PROCEDURE POKE(ADDR, VALUE : INTEGER);
VAR
 LOC : DUAL;

BEGIN {POKE}
 LOC.INT := ADDR;
 LOC.PTR^ := VALUE;
END; {POKE}

FUNCTION PEEK(ADDR : INTEGER) : INTEGER;
VAR
 LOC : DUAL;

BEGIN {PEEK}
 LOC.INT := ADDR;
 PEEK := LOC.PTR^;
END; {PEEK}

procedure swapbyte(var x:integer);

(* This procedure takes a word and reverses the order of the bytes *)

   type
      byteword = record
         case boolean of
         true: (addr:integer);
         false:(bytes: packed array[1..2] of byte);
         end;

   var
      word:  byteword;
      tbyte: byte;

   begin
      with word do
         begin
         addr := x;
         tbyte := bytes[1];
         bytes[1] := bytes[2];
         bytes[2] := tbyte;
         x := addr;
         end;  (* with statement *)
      end;  (* procedure *)

   procedure wrtvdpaddr (vdpaddr : integer);

   (* This procedure initializes the VDP ram chip to read/write from the *
    * address passed in the parameter vdpaddr.  *)

      begin
      cpuaddr.int := wrtaddr;
      swapbyte( vdpaddr );
      cpuaddr.ptr^ := vdpaddr;
      swapbyte( vdpaddr );
      cpuaddr.ptr^ := vdpaddr;
      end;  (* procedure *)

   function rdvdp (var vdpaddr : integer) : integer;

   (* This function reads a byte of data from the VDP ram address specified *
    * in the parameter vdpaddr.  *)

      begin
      wrtvdpaddr( vdpaddr );
      cpuaddr.int := rddata;
      rdvdp := cpuaddr.ptr^ div 256;  (* Right justify byte in word *)
      vdpaddr := vdpaddr + 1;
      end;  (* procedure *)

   procedure wrtvdp( var vdpaddr : integer;
                         data    : integer);

   (* This procedure writes the byte of data passed in the parameter *
    * data to the VDP ram address specified in vdpaddr.  *)

      var
         temp : integer;

      begin
      temp := vdpaddr + wrtenab;  (* Write enable the address *)
      wrtvdpaddr(temp);
      cpuaddr.int := wrtdata;
      cpuaddr.ptr^ := data * 256; (* Left justify byte in word and write *)
      vdpaddr := vdpaddr + 1;
      end;  (* procedure *)

   begin (* main program *)
    MONTHSTR[1] := 'JAN';
    MONTHSTR[2] := 'FEB';
    MONTHSTR[3] := 'MAR';
    MONTHSTR[4] := 'APR';
    MONTHSTR[5] := 'MAY';
    MONTHSTR[6] := 'JUN';
    MONTHSTR[7] := 'JUL';
    MONTHSTR[8] := 'AUG';
    MONTHSTR[9] := 'SEP';
    MONTHSTR[10] := 'OCT';
    MONTHSTR[11] := 'NOV';
    MONTHSTR[12] := 'DEC';
    
    unitno := 6; (* select PRINTER: *)
    pabname := 'PIO';
    for j := 1 to 2 do
     begin
      cpuaddr.int := pabtbl + unitno * 2;
      vdpaddr := cpuaddr.ptr^ + 17;
      savevdpaddr := vdpaddr;

      period := 0;
      for i := 1 to length(pabname) do
       begin
        if (period = 0) and (pabname[i] = '.') then
         period := i - 1;
        if pabname[i] in ['a'..'z'] then
         pabname[i] := chr(ord(pabname[i])-32);
       end;  (* for loop *)

      if period = 0 then
       period := length(pabname);
      vdpaddr := savevdpaddr-17;
      for i := 1 to 2 do
       wrtvdp(vdpaddr,0);
      wrtvdp(vdpaddr, period);
      for i := 1 to 3 do
       wrtvdp(vdpaddr, 0);
      vdpaddr := savevdpaddr;
      for i := 0 to length(pabname) do
       wrtvdp(vdpaddr, ord(pabname[i]));
      unitclear(unitno);

      unitno := 7; (* select REMIN/REMOUT: *)
      pabname := 'RS232/1.BA=2400.DA=8.PA=N.EC';
     end;

  GOTOXY(1,2);
  WRITELN;
  writeln('PRINTER:      PIO');
  writeln('REMIN/REMOUT: RS232/1.BA=2400.DA=8.PA=N.EC');
  writeln;


  (* prompt for the date and set it *)
 MONTHNAME := 'JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC';

 {GET SYSTEM DATE}
 WORD.VALUE := PEEK(DATELOC);
 YEAR := WORD.BYTES[1] DIV 2;
 WORD.VALUE := WORD.VALUE * 16;
 DAY := ORD((ODD(WORD.BYTES[1])) AND (ODD(31)));
 MONTH := WORD.BYTES[2] DIV 16;
 MSTRING := COPY(MONTHNAME,MONTH * 3 - 2, 3);
 
 {GET SYSTEM TIME}
 UNITREAD(4, DIRECTORY, SIZEOF(DIRECTORY), 1);
 HR := DIRECTORY.HR;
 MIN := DIRECTORY.MIN;
 SEC := DIRECTORY.SEC;
 
 WRITELN('LAST BOOT:    ',DAY,'-',MSTRING,'-',YEAR,'  ',HR,':',MIN,':',SEC);

 {GET CURRENT DATE}
 WRITELN('CURRENT DATE:',CHR(7));
 CDATE(DAY, DOW, MONTH, YEAR);
 CTIME(SEC, MIN, HR);
 GOTOXY(14, 7);
 WRITELN(DAY,'-',MONTHSTR[MONTH],'-',YEAR,'  ',HR,':',MIN,':',SEC);
 
 {UPDATE SYSTEM DATE IN RAM}
 I := (YEAR * 512) + (DAY * 16) + MONTH;
 POKE(DATELOC, I);

 {UPDATE ROOT DISK WITH DATE}
 DIRECTORY.HR := HR;
 DIRECTORY.MIN := MIN;
 DIRECTORY.SEC := SEC;
 DIRECTORY.DLASTBOOT := I;
 UNITWRITE(4,DIRECTORY,SIZEOF(DIRECTORY),1);
END.



 

 

 

EDT-COMP.dsk

  • Like 4
Link to comment
Share on other sites

So I was reviewing the SYSTEM.STARTUP code and realized that I was not reserving space for sectors 0 to 2 in the DIRTYPE record, and so UNITREAD and UNITWRITE were retrieving that record starting at sector 0 and thus fetching or writing from/to the wrong location, and yet everything still works normally but really shouldn't. @apersson850's startup file does include fillers in the DIRTYPE record for sectors 0-2.

What gives?

 

DIRTYPE = RECORD
       *** HERE I SHOULD HAVE HAD 3 FILL ARRAYS EACH 256 BYTES LONG
           TO ACCOUNT FOR SECTORS 0-2 ***
       TFILL1 : PACKED ARRAY[0..11] OF CHAR;    {SECTOR 3}
       HR : INTEGER;
       MIN : INTEGER;
       SEC : INTEGER;
       TFILL2 : PACKED ARRAY[0..237] OF CHAR;
       FILL1 : PACKED ARRAY[0..19] OF CHAR; (* SECTOR 4, PASCAL DIRECTORY *)
       DLASTBOOT : INTEGER;
       FILL2 : PACKED ARRAY[0..489] OF CHAR; (* SECTORS 4 AND 5 *)
      END;

 

  • Sad 1
Link to comment
Share on other sites

On 8/2/2024 at 9:01 AM, apersson850 said:

There is a special mode bit for physical disk access, i.e. block 0 is sectors 0 and 1. Otherwise block 0 is sectors 4 and 5, since 0-3 are reserved for the standard disk directory headers.

I still don't understand why this worked

Link to comment
Share on other sites

Posted (edited)

You used unitread/write to start accessing logical disk block 0, which is in sectors 4-5. Looking at your code, you access block 1, which is in sectors 6-7. The p-system's directory is in sectors 4-7, so you're accessing the latter part of that. It's usually not used on a system disk, as it tend to have rather larger files and thus not very many. Your program will probably cause issues on disks with more files.

In my program I used unitread/unitwrite in physical access mode, which implies that block 0 is in sectors 0-1.

The optional control flag at the end of the parameter list determines the mode. The second least significant bit (value 2) is the logical/physical access bit.

 

This is from the Texas Instruments Professional computer UCSD p-system Internal Architecture software library manual.

image.thumb.png.179dd9ff9eab64828ca5ad62a025b50c.png

Note that there's an error in bit numbers in the last two rows. Should be Bits 4-12 and then Bits 13-15.

The 99/4A uses one of the user-defined bits (bit 14) to control the buffer location as being CPU or VDP RAM. This makes it possible to read VDP data directly from disk into the VDP RAM where you want it to be. Like character definitions or screen content.

Edited by apersson850
Link to comment
Share on other sites

There is no mention of a "control" parameter in the compiler manual for UNITREAD/UNITWRITE. In your startup file, you have the following:

 

(* Write information back to directory *)
unitwrite(4,directory,sizeof(directory),0);

 

Where exactly is that control parameter? Is it that last integer value? If it is then its not the correct value per your explanation and besides the manual only mentions that it's meant for VDP access if set to 16384... I must be missing something obvious here...

Link to comment
Share on other sites

Not precisely on topic, but, here is a 1979 paper on creating the TI PASCAL compiler.

 

This is the source-code-portable Pascal, designed for use anywhere in TI.  They were really going all-in on Pascal--big color advertisements in 1980 in Mini-Micro Systems. 

 

TI Pascal adopted several language extensions, including new forms of CASE, WITH, FOR, and forbidding GOTO (ESCAPE is used to break out of a loop).  

 

The compiler produces Common Intermediate Language (CIL), which is accepted by a Machine-Independent OPTimizer.  Finally, code generators were made for TI-990 , TI-980, and IBM 370.  The whole process was kept within 64K of memory. 

  • Like 4
Link to comment
Share on other sites

Join the conversation

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

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

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

×   Your previous content has been restored.   Clear editor

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

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...