Jump to content
IGNORED

Pascal on the 99/4A


apersson850

Recommended Posts

Posted (edited)

The p-system doesn't care about the disk format at all. It just uses the sector read/write subroutine and let the low level bios figure out how to access the disk.

 

When using bitmap with the p-system you must move the keyboard buffer, since it's disturbing your graphics otherwise.

 

Why save the VDP memory prior to doing bitmap graphics? There's nothing to save, since that's the whole reason for why you can reserve the space.

Edited by apersson850
Link to comment
Share on other sites

1 hour ago, apersson850 said:

Why save the VDP memory prior to doing bitmap graphics? There's nothing to save, since that's the whole reason for why you can reserve the space.

It seemed like the safe thing to do as I frankly was not sure if there was something worth preserving. It was painless enough to do :) 

One question: Do I need to update the Pascal VDP registers vr1-7 in low memory when I switch to bitmap before calling the keyboard scan routine?

Also your code mentions a keyboard layout area. What is that?

Link to comment
Share on other sites

Regarding VDP memory:

Either you can do the bitreserve without any issue. If you can, then that's because there is nothing worth saving in VDP memory in that area which the bitmap mode needs.

Or you can't do bitreserve, since the area needed is already occupied by something the p-system needs. That "something" is then code, since that's the only thing the p-system will store in that area. If there is code there you need to save it prior to showing bitmap images. But, and that's a big but, that also implies that you most likely can't return from your assembly code handling bitmap, since if you want to do that, you have to restore VDP memory and then you destroy your image. Or you don't restore just because you return and then you may try to run the bitmap image as code. Which of course will not end well.

 

Thus the result is that saving the VDP is either not necessary or doesn't make any difference.

 

The p-system holds a keyboard buffer (the type ahead queue) and information about which keys are to be interpreted for certain functions in VDP RAM. For some reason - maybe they didn't at the time that decision was taken realize that they would get some unused RAM left over at the top of the low memory expansion.

You have to move these things out of the way for the bitmap mode. Fortunately there are some holes in the VDP RAM usage for bitmap.

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

So here's my question about backing up the VDP RAM. The lower 4K will hold the standard character definitions which will get overwritten by a bitmap image. I did notice that even without manually restoring that area, somehow the definitions get restored when I return from bitmap. How is that possible?

I knew about the keyboard buffer, but not the layout area. Is that the area which hold the key information you mention (120 bytes)?

Also what about the Pascal VDP registers? You update them in your code after changing the standard VDP registers and I'm not too clear as to why.

It's really important for me to understand fully how to do the bitmap switch back and forth while preserving as much function as possible, hence why I am peppering you with questions. You're the only person alive as far as I know with such in-depth knowledge of the system and I'm trying to leech as much of that priceless info as possible before it's too late! 😁

I also heard that you will be writing a series of articles on the p-system for the Chicago User Group newsletter. I'm looking forward to reading those.

  • Like 5
Link to comment
Share on other sites

Posted (edited)

Here are some pieces of the code. I've added some more comments (not syntactically correct to assemble).

What's shown here is how to enter into bitmap mode. The last part clears the screen and loads values into all VDP memory that's used for bitmap. It can be called separately to just clear the screen.

Then there's a corresponding routine not copied below that returns from bitmap mode to something normal. It kind of moves everything back to where it came from, character definitions included. That's why various pointers in the .EQU section have two values. KEYBUF1 is used normally by the p-system, KEYBUF2 when the bitmap mode is active and so on.

If you don't take care of the character definitions it could be that they are re-loaded from OS:SYSTEM.CHARAC when your program terminates. I've not checked that. If you have looked at my screenshots you may have noticed that I have a different default character set than you have. You can make your own character definitions and store as *SYSTEM.CHARAC

Note that I set up to be able to use sprites, but I haven't done anything to handle that. You can not use the supplied unit sprite, since it will assume the sprite table to be in the normal place, where it can't be with bitmap.

 

SP       .EQU 10
PASCALWS .EQU 8380H

VDPRD    .EQU 8800H     ;VDP read data address
VDPWD    .EQU 8C00H     ;VDP write data address
VDPWA    .EQU 8C02H     ;VDP write address address

KEYBUFPNT: .EQU 288AH   ;Keyboard buffer pointer
LAYOUTPNT: .EQU 288CH   ;Keyboard layout pointer
KEYBUF1  .EQU 0BE0H     ;Normal key buffer
KEYBUF2  .EQU 1B80H     ;Bit-map key buffer
LAYOUT1  .EQU 0D80H     ;Normal layout area
LAYOUT2  .EQU 1BA0H     ;Bit-map layout area

REGCOPY  .EQU 2810H     ;PME copy table of VDP R1..R7
PATTERN1 .EQU 0         ;Pattern generator table
PATTERN2 .EQU 2000H
COLTAB1  .EQU 0BC0H     ;Color table
COLTAB2  .EQU 0
IMAGE1   .EQU 0800H     ;Screen image table
IMAGE2   .EQU 1800H
SAB1     .EQU 0C00H     ;Sprite attribute table
SAB2     .EQU 1B00H
SAVE2A   .EQU 1C18H     ;Otherwise unused area between tables
;                        Now used to hold character definitions
SAVE2B   .EQU 3800H     ;Additional save area

This is where bitmap mode is set up and the screen is cleared.

.PROC BITMAP,1
         .DEF VMBR,VMBW,VSBW,VSBR,VWTR,VFILL
         .DEF INITSTUFF

Start by moving the beyboard type ahead buffer out of harm's way and update the pointer.
         LI   R0,KEYBUF1 ;Move keyboard buffer
         MOV  *SP+,R1    ;Get address of general buffer
         LI   R2,20H     ;Size of buffer
         BLWP @VMBR
         LI   R0,KEYBUF2
         BLWP @VMBW
         MOV  R0,@KEYBUFPNT

Do the same with the keyboard layout area.
         LI   R0,LAYOUT1 ;Move layout area
         LI   R2,120     ;Size of area
         BLWP @VMBR
         LI   R0,LAYOUT2
         BLWP @VMBW
         MOV  R0,@LAYOUTPNT

Set up VDP registers and save a copy for the PME, in case it thinks it should restore them.
         LI   R0,81A0H  ;Blank screen
         BLWP @VWTR
         LI   R0,8002H  ;Set control registers for bit map mode
         BLWP @VWTR     ;No PME copy of VDP R0
         LI   R0,8206H
         BLWP @VWTR
         MOV  R0,@REGCOPY+2     ;Update PME copies of VDP regs
         LI   R0,837FH
         BLWP @VWTR
         MOV  R0,@REGCOPY+4
         LI   R0,8407H
         BLWP @VWTR
         MOV  R0,@REGCOPY+6
         LI   R0,8536H
         BLWP @VWTR
         MOV  R0,@REGCOPY+8

Save the character definitions as they are when entering bitmap. I use them in the procedure to write a character anywhere on the bitmap screen.
All of them doesn't fit in the same place.
         LI   R0,PATTERN1       ;Save first 24 bytes of pattern table
         LI   R2,24             ;Corresponds to chr(0)..chr(2)
         BLWP @VMBR
         LI   R0,SAVE2B
         BLWP @VMBW
         LI   R0,PATTERN1+24    ;Save next 1000 bytes
         LI   R2,1000           ;Corresponds to chr(3)..chr(127)
         BLWP @VMBR             ;chr(128)..chr(255) not saved
         LI   R0,SAVE2A
         BLWP @VMBW
         
         LI   R0,SAB2   ;Disable first sprite
         LI   R1,0D000H
         BLWP @VSBW

Finalize the setup by clearing the screen and loading all values in the character, pattern and color tables.
; This is an entry point for initbitmap.
Here you start running if you are already in bitmap mode, but want to erase all graphics to clear the screen.
;
INITSTUFF:
         LI   R0,COLTAB2        ;Set color table to black on transparent
         LI   R1,1000H
         LI   R2,1800H
         BLWP @VFILL

         LI   R0,IMAGE2 .OR 4000H   ;Initiate screen image table
         SWPB R0
         MOVB R0,@VDPWA
         SWPB R0
         MOVB R0,@VDPWA
         LI   R0,3      ;00..FF repeated three times
LOOP2    CLR  R1
         LI   R2,100H   ;Counter
LOOP1    MOVB R1,@VDPWD
         AI   R1,100H
         DEC  R2
         JNE  LOOP1
         DEC  R0
         JNE  LOOP2

         LI   R0,PATTERN2       ;Set pattern table to all blank
         CLR  R1
         LI   R2,1800H
         BLWP @VFILL

         LI   R0,81E0H  ;Enable screen in graphics mode
         BLWP @VWTR
         MOV  R0,@REGCOPY

         B    *R11

 

As a general comment: Feel free to understand what it's doing, but use my unit to get into and out of bitmap mode, so we have the same base to build on. I've got some ideas about implementing a store/retreive function of part of the screen, which I of course would base on my own turtlegraphics unit. If I come to that, and you do some other enhancement based on the same unit, then we can easily combine the result of our efforts and come up with a better unit.

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

On 4/1/2024 at 8:14 PM, Asmusr said:

Have you tried -ioport:peb:slot2 samsmem ?

Yes... ./mame ti99_4a -window -nomouse -skip_gameinfo -autoframeskip -natural -ioport peb  -ioport:peb:slot2 samsmem -ioport:peb:slot8 bwg -ioport:peb:slot8:bwg:2 525dd -ioport:peb:slot3 pcode -flop1 "software/ti99_pcode/SAMSUTIL.dsk"

 

image.thumb.png.d893bb33f2a2ae500374ff1079e3641d.png

Link to comment
Share on other sites

3 hours ago, gferluga said:

Yes... ./mame ti99_4a -window -nomouse -skip_gameinfo -autoframeskip -natural -ioport peb  -ioport:peb:slot2 samsmem -ioport:peb:slot8 bwg -ioport:peb:slot8:bwg:2 525dd -ioport:peb:slot3 pcode -flop1 "software/ti99_pcode/SAMSUTIL.dsk"

 

image.thumb.png.d893bb33f2a2ae500374ff1079e3641d.png

It's actually a bug in my code. When reading the SAMS registers, a real SAMS card will only return the MSB (the page #) but not the LSB, whereas Classic 99 will return both as a word instead of a byte. MAME accurately emulates the SAMS behavior, including how the registers are read, which is why the program failed to detect the card. Same behavior on real hardware.

Attached is a corrected version (replacing a C instruction by a CB one...) which fixes the issue. Sorry about that.

 

SAMSUTIL.dsk

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

Just now, TheBF said:

You are allowed one bug a week I believe. 

 I am always over my limit. 

 

(That's my weird way to say I think you are doing amazing stuff with the P code card.) ;) 

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

2 hours ago, Vorticon said:

When reading the SAMS registers, a real SAMS card will only return the MSB (the page #) but not the LSB, whereas Classic 99 will return both as a word instead of a byte. MAME accurately emulates the SAMS behavior, including how the registers are read, which is why the program failed to detect the card.

Classic99 is perfectly accurate for the 32MB card it's emulating, thank you. ;) If it didn't return both bytes you wouldn't be able to tell what page was mapped.

 

Now whether that 32MB card will ever be released I don't know.

  • Like 2
Link to comment
Share on other sites

25 minutes ago, Tursi said:

Classic99 is perfectly accurate for the 32MB card it's emulating, thank you. ;) If it didn't return both bytes you wouldn't be able to tell what page was mapped.

 

Now whether that 32MB card will ever be released I don't know.

And in fact the hardware on the 1M card does the same as we can see in the image.

Here I turn on the card and then dump the registers at >4000.

 

 

 

 

COM1 - Tera Term VT 2024-04-02 10_17_03 PM.png

  • Like 1
Link to comment
Share on other sites

40 minutes ago, TheBF said:

And in fact the hardware on the 1M card does the same as we can see in the image.

Here I turn on the card and then dump the registers at >4000.

 

 

 

 

COM1 - Tera Term VT 2024-04-02 10_17_03 PM.png

Not on my 1meg card. The detection failed just as in MAME with my original code. Are there different versions of the card?

  • Like 1
Link to comment
Share on other sites

1 hour ago, Tursi said:

Classic99 is perfectly accurate for the 32MB card it's emulating, thank you. ;) If it didn't return both bytes you wouldn't be able to tell what page was mapped.

 

Now whether that 32MB card will ever be released I don't know.

True, but it's still problematic if one wants to support current existing hardware. 

There used to be an option to choose the size of the SAMS in Classic99, but it's now grayed out. 

  • Like 1
Link to comment
Share on other sites

Could it be that different 1M cards work in different ways (some return the register value in both MSB and LSB and others only return it in the MSB)? I implemented the behavior that TheBF demonstrated in JS99er, but that broke the Stevie editor, so I changed it back.

  • Like 4
Link to comment
Share on other sites

I got the keyboard scanning routine to work in bitmap mode following @apersson850's method of relocating the keyboard buffers, but I also needed to restore the Pascal VR1 in low memory prior to exiting the routine as it seemed that the KSCAN routine was affecting it somehow. Otherwise I would get a garbage screen from an incorrectly set VR1. I don't have a clear explanation for this because the scanning routine copies the Pascal VRs to the RAMPAD and KSCAN is supposed to only use that area and should not affect the Pascal VR's. 

More often than not the p-system feels like it's finely balanced on the tip of a needle, and any unsanctioned activity like bitmap access will upset that balance and lead to unexpected behavior... Still waiting for that wig Anders...

Link to comment
Share on other sites

13 hours ago, Vorticon said:

True, but it's still problematic if one wants to support current existing hardware. 

There used to be an option to choose the size of the SAMS in Classic99, but it's now grayed out. 

 

12 hours ago, Asmusr said:

Could it be that different 1M cards work in different ways (some return the register value in both MSB and LSB and others only return it in the MSB)? I implemented the behavior that TheBF demonstrated in JS99er, but that broke the Stevie editor, so I changed it back.

 

To be compatible with current SAMS hardware, the returned LSB should always be ignored when reading the SAMS registers. SAMS hardware merely repeats the page number of the MSB in both bytes, whereas Classic99 does, in fact, return the bank# in the LSB and the page# in the MSB.

 

...lee

  • Like 4
Link to comment
Share on other sites

37 minutes ago, Lee Stewart said:

To be compatible with current SAMS hardware, the returned LSB should always be ignored when reading the SAMS registers. SAMS hardware merely repeats the page number of the MSB in both bytes, whereas Classic99 does, in fact, return the bank# in the LSB and the page# in the MSB.

If I wrote a program for the TI, I would never rely on the LSB unless I had detected a card bigger than 1 MB. But as the developer of an emulator, I would like to know the most correct way to emulate a 1 MB card. It sounds like there are at least 2 types of card: one that returns zero in the LSB (Vorticon + retroclouds) and one that returns a copy of the MSB (TheBF + emulated in MAME).  

  • Like 2
Link to comment
Share on other sites

The MAME implementation is not suitable as a reference, since I simply did the following:

 

	if (m_access_mapper && in_dsr_space(offset, false))
	{
		*value = m_mapper[(offset>>1)&0x000f];
	}

 

So it seems as if I did it the simple way: If the access to the mapper registers is active, and the address is within the DSR space, get the value by indexing the mapper chip, where the index is gained by shifting the address one to the right and masking away all but the last 4 bits. This means that odd addresses are treated like even addresses (losing the rightmost bit) and that the mapper is mirrored throughout the DSR area.

 

I'd have to study the schematics more closely to give a meaningful answer.

  • Like 4
Link to comment
Share on other sites

1 hour ago, mizapf said:

The MAME implementation is not suitable as a reference, since I simply did the following:

 

	if (m_access_mapper && in_dsr_space(offset, false))
	{
		*value = m_mapper[(offset>>1)&0x000f];
	}

 

So it seems as if I did it the simple way: If the access to the mapper registers is active, and the address is within the DSR space, get the value by indexing the mapper chip, where the index is gained by shifting the address one to the right and masking away all but the last 4 bits. This means that odd addresses are treated like even addresses (losing the rightmost bit) and that the mapper is mirrored throughout the DSR area.

 

I'd have to study the schematics more closely to give a meaningful answer.

I tried it now, and my real sidecar SAMS is also returning a duplicate of the MSB in the LSB (inspected using Easybug) and it's mirrored throughout the DSR area.

  • Like 3
Link to comment
Share on other sites

16 hours ago, Vorticon said:

True, but it's still problematic if one wants to support current existing hardware. 

There used to be an option to choose the size of the SAMS in Classic99, but it's now grayed out. 

It actually never worked. It was always 1MB until I was asked to support the 32MB version. I greyed it out to remove the confusion.

 

I do recognize this causes some issues for some people, but nobody has ever asked me to fix it! ;)

 

  • Like 3
Link to comment
Share on other sites

I think a challenge is that there are multiple iterations of AMS-like memory cards. I'm not at all surprised that some return 0 and some return a duplicate. This is not entirely unlike the issue we discussed a decade or so ago that the TI memory expansion card, based on DRAM, tends to init with an alternating pattern of 00 FF, while SRAM expansions tend to initialize with 00 (and that this actually broke one or two programs that assumed).

 

It's unclear whether the extended card that I implemented will ever be released, but Nouspikel also describes such a thing to take it to 16MB:

https://www.unige.ch/medecine/nouspikel/ti99/superams.htm

 

For maximum flexibility, anything not part of the actual specification should generally be treated as "ignore" rather than to assume a pattern observed there will be consistent. This is standard practice in most embedded hardware.

 

@Asmusr's suggestion was the one that I thought had been adopted - to simply ignore the LSB unless you are expecting to find more than 1MB. I don't remember now, but we had someone build a top-end AMS tester a few years ago. Does it handle more than 1MB? If yes, what was its approach?

 

My understanding was treating it in this manner should allow both the 1MB card and the 32MB card to function with the same code. Is that untrue?

 

None of this to be meant that you can't write whatever code you want. I mean, we don't have a huge community and it's all for fun anyway. But understanding what does and doesn't work, and what practices are followed, can help the emulation get better too. ;)

 

  • Like 1
Link to comment
Share on other sites

Well one way that would universally work would be to write a discordant value, say >0102 to the registers, then on a first pass test the MSB. If it passes, then test for the whole word. If it passes again then we have a card larger than 1 meg, otherwise it's smaller or equal. 

        LI  R1,>0102
        MOV R1,@>401E
        CB  R1,@>401E
        JNE NOCARD
        C   R1,@>401E
        JNE SMCARD
        JMP LGCARD

 

  • Like 1
Link to comment
Share on other sites

1 hour ago, Tursi said:

we had someone build a top-end AMS tester a few years ago. Does it handle more than 1MB? If yes, what was its approach?

 

I know nothing about implementation, but JediMatt's RAM tester sees greater than 1MB on Classic99, as well as JasonAct's PicoPEB:

 

sams-test-c99.thumb.png.c2818b2f81ea6543d76b4bdbe01aaa35.png 

picopeb-sams-2mb.thumb.jpg.4b1aef3d2b3e575aa93bf323b3ecb151.jpg

According to the github, the tester will see up to 16MB: https://github.com/jedimatt42/ti994a-memtest

 

  • Like 4
Link to comment
Share on other sites

I applied my little scheme above to detect large capacity SAMS cards and it works.

Spoiler
 .func samsinit
;initialize the sams card and verify card is present
;returns 0 for absent, 1 if <= 1Mb and 2 if > 1 Mb 
;usage: statusint := samsinit

        .def    procret,pmeret,pcodeon,pcodoff
        mov     r11,@procret
        bl      @pcodoff
        li      r12,1e00h       ;cru address of sams card
        sbo     0               ;turn card on
        li      r1,0ff00h
        li      r0,4000h        ;start address of sams registers
nxtpage ai      r1,0100h        ;increment page number starting at 0
        mov     r1,*r0+         ;load page number into sams register
        ci      r0,4020h        ;beyond last register (401eh)?
        jlt     nxtpage
        cb      r1,@401eh       ;if match then card present
        jne     nocard
        li      r1,0102h
        mov     r1,@401eh
        c       r1,@401eh
        jeq     lgcard
        li      r2,1
        jmp     endinit
lgcard  li      r2,2
        jmp     endinit
nocard  clr     r2
endinit li      r1,0f00h
        mov     r1,@401eh
        mov     r2,*r10         ;place card indicator on return stack
        sbz     0               ;turn sams card off
        bl      @pcodeon
        mov     @procret,r11
        b       *r11

 

And here it is on real hardware with my 1mb card:

20240404_072716.thumb.jpg.2f3b53cb808250ef2cf11adf1d860acb.jpg

  • Like 5
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...