+Vorticon Posted March 28 Share Posted March 28 2 hours ago, apersson850 said: You will also gain the advantage of compiling at twice the speed on the real machine, with the compiler on the RAM-disk. Even faster if source and code are on the RAM-disk too. Now that would definitely be a good incentive. That said, I recently purchased an IDE drive card for the TI with an RTC which I'm planning on building it this week, and my hope is that there might be a way to use that as an additional drive in my p-system. It may not be as fast as a RAM disk, but this will offset by the fact that contents will obviously be non-volatile. But going back to the SAMS, since data can only be access through a 4K window at >2000 in the p-system, I have no clue how to get this scheme to work as an alternate code pool seamlessly, particularly since transparent 4K paging will be required for larger data or programs, not to mention that any screen I/O will corrupt the data while the card is active and will not be visible. I am intrigued enough to consider it, but it may be a little beyond my pay grade. If you want, perhaps you can give us an outline of how one could accomplish this for starters, keeping in mind that I am not engineer/developer anything and I only do this for the intellectual stimulation 2 Quote Link to comment Share on other sites More sharing options...
apersson850 Posted March 28 Author Share Posted March 28 No, no, no, not an alternate code pool. I'm talking about making it available as a drive (volume in p-system vocabulary), just a much faster such drive. What you do need is a place to have a DSR to handle it, because it must take command like a disk drive, where the system assumes a CRU address to enable the DSR and an entry address to access it. Since the system will assume it to be a normal DSR, the BIOS will already have disabled the p-code card and will re-enable it before returning, so you don't need to worry about that. You'll implement the equivalent of sector read/write (subprogram 10H on your "disk controller"). That's all it takes. That's the only thing the p-system uses. What will call you is the equivalent of the unitread/unitwrite procedure in the SBIOS, which will ask for a transfer to or from the drive. In the SAMS, you'll have to map that 4 K window to one page which is available as normal memory and active when no access to the RAMdisk is active. When an access is active, you'll be asked for a particular 256 byte sector to map in. You have to calculate which page that is in and which offset it has, read/write that sector to the buffer address unitwrite/-read will ask for, return the standard page in SAMS and exit. There are some tricks involved in convincing the p-system that there is one more drive controller in the system, but that you'll face already if you want to add an IDE controller in parallel to the standard disk controller. Thinking about the feasibility about this - I'm not sure without checking in the code or other documentation how high a sector number you can send to the 10H subprogram. The p-system can handle 32768 blocks, but that's 65536 sectors, so it maxes out what an unsigned 16-bit value can hold. Splitting it in more than one file doesn't help, since they'll still have different sectors. Splitting the file over two virtual volumes on one SAMS card will help and doesn't make the driver much more complicated. 1 Quote Link to comment Share on other sites More sharing options...
Asmusr Posted March 28 Share Posted March 28 (edited) 6 hours ago, apersson850 said: If I understand you correctly, SAMS is accessed via a window, into which you map whichever physical memory page you like in the SAMS device. That window may be a memory expansion part, like 2000-3FFFH or it could be the DSR page, 4000-5FFFH. Now I may have misunderstood the details (I've not worked with SAMS at all), but hopefully I have the core idea correct here. Unfortunately SAMS cannot map into in the DSR space, >4000 - >5FFF - only into the normal expansion RAM areas. And pages are switched not using CRU but by writing to registers mapped into >4000 - >401f. Edited March 28 by Asmusr Quote Link to comment Share on other sites More sharing options...
+Vorticon Posted March 28 Share Posted March 28 37 minutes ago, Asmusr said: Unfortunately SAMS cannot map into in the DSR space, >4000 - >5FFF - only into the normal expansion RAM areas. And pages are switched not using CRU but by writing to registers mapped into >4000 - >401f. Right. So I assume that rules out creating a DSR for it. Mind you I have zero understanding of how DSR's are set up and programmed outside of just a very superficial general concept. Is there a document somewhere that has a reasonable explanation of how one might create a DSR? Quote Link to comment Share on other sites More sharing options...
Asmusr Posted March 28 Share Posted March 28 2 hours ago, Vorticon said: Right. So I assume that rules out creating a DSR for it. Mind you I have zero understanding of how DSR's are set up and programmed outside of just a very superficial general concept. Is there a document somewhere that has a reasonable explanation of how one might create a DSR? Maybe this? https://www.unige.ch/medecine/nouspikel/ti99/headers.htm I have been thinking about writing a RAM disk DSR for the SAMS for years, but I thought the only option would be to put it (or part of it) in a GROM, and that wouldn't work for some implementations of DSRLNK. But it could be different for the p-code card. Anyway, when thinking about a memory manager for SAMS, splitting it into 4096 sectors of 256 bytes (which would be the smallest amount of memory you could allocate) might still be a good idea, even though you wouldn't access the sectors as files. You could use one page as a map of which sectors were allocated, and use other concepts from file systems like file descriptor records. 1 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted March 28 Share Posted March 28 4 hours ago, Vorticon said: Is there a document somewhere that has a reasonable explanation of how one might create a DSR? DSR_spec_for_ti994a_PC_V2_0_03_28_1983.pdf 1 Quote Link to comment Share on other sites More sharing options...
apersson850 Posted March 28 Author Share Posted March 28 (edited) Now I've read about how SAMS work, so I know what I'm talking about. There are a couple of options, some unique to what you can do with the p-system. One way is to do like I did with my own RAM-disk. Since it uses RAM everywhere, across the whole address space 0000-FFFFH, I stored the DSR in RAM on my IO-card. What kind of card it is doesn't matter (it's my own design - only one exists). The important thing is that it has the DSR in RAM. Since part of my RAM-disk is in the DSR space, I have to turn off the DSR and run the code to reach that elsewhere. I solved that by saving a part of some other memory in the RAM for the DSR, copy code from the DSR out to the saved area, jump there, turn off the DSR from the outside and map in the RAM-disk memory over the DSR space, access the desired sector, turn the DSR back on again, jump back into it, restore the saved memory and return. A lot of maneuvers but much faster than a standard floppy. These tricks are needed only for that particular memory segment, so they aren't used for all other memory. With the p-system there is also another way. Normally all DSR programs must be in the 4000-5FFFH range. But the p-system does a prescan of needed DSRs at boot time and stores a table with information about the CRU and entry address. Thus it's possible to add the RAM-disk DSR after boot (you need to do that anyway, since it will only search for one disk controller at start) by storing the CRU address of the SAMS (typically 1E00H, I've noticed) and then a fake entry address to the DSR elsewhere than in DSR space. If you have a cartridge with RAM you can store it there. Even the original Mini Memory would do, but there are other options too today. Then you manage the SAMS from that program in Mini Memory and just return to where called from when you are ready. During the access, you can control the map registers as you like and have for example 2000-3FFFH as your window into the SAMS world. You don't even have to save anything, since that will be in the default SAMS page for that part of the memory. What you implement is a sector read/write program, which acts the same as it would do if it was in a disk controller. You'll just store or read the sector you're asked to do, and that's it. A third version of this is that you use the high end of 2000-3FFFH, which seems unused by the p-system. That's easier to verify today, when we can check with an emulator if it's touched. But then you can of course not use the 2000-3FFFH as a window into the SAMS repository, since then you'll switch out yourself. Software suicide. You have to use a window somewhere in the A000-FFFFH range instead. For the p-system the whole thing is simplified significantly by the fact that you need to implement sector read/write and nothing more. That's the only thing the p-system uses. I've done that a couple of times now, both for my own RAM-disk and for a Horizon card, where certain versions of the DSR aren't compatible with the p-system. Edited March 28 by apersson850 3 Quote Link to comment Share on other sites More sharing options...
JasonACT Posted March 28 Share Posted March 28 2 minutes ago, apersson850 said: A third version of this is that you use the high end of 2000-3FFFH, which seems unused by the p-system. That's easier to verify today, when we can check with an emulator if it's touched. But then you can of course not use the 2000-3FFFH as a window into the SAMS repository, since then you'll switch out yourself. Software suicide. SAMS pages in 4K blocks, so can't you have your code at the high part of >3000 and switch pages at >2000 without causing issues like this? Quote Link to comment Share on other sites More sharing options...
+Vorticon Posted March 29 Share Posted March 29 2 hours ago, apersson850 said: With the p-system there is also another way. Normally all DSR programs must be in the 4000-5FFFH range. But the p-system does a prescan of needed DSRs at boot time and stores a table with information about the CRU and entry address. Thus it's possible to add the RAM-disk DSR after boot (you need to do that anyway, since it will only search for one disk controller at start) by storing the CRU address of the SAMS (typically 1E00H, I've noticed) and then a fake entry address to the DSR elsewhere than in DSR space. If you have a cartridge with RAM you can store it there. Even the original Mini Memory would do, but there are other options too today. Then you manage the SAMS from that program in Mini Memory and just return to where called from when you are ready. During the access, you can control the map registers as you like and have for example 2000-3FFFH as your window into the SAMS world. You don't even have to save anything, since that will be in the default SAMS page for that part of the memory. What you implement is a sector read/write program, which acts the same as it would do if it was in a disk controller. You'll just store or read the sector you're asked to do, and that's it. That seems to be the best path to me. The Mini Memory requirement in my view is probably the most universal solution to store the DSR. I have some serious reading to do... 1 1 Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted March 29 Share Posted March 29 2 hours ago, apersson850 said: A third version of this is that you use the high end of 2000-3FFFH, which seems unused by the p-system. 2 hours ago, JasonACT said: SAMS pages in 4K blocks, so can't you have your code at the high part of >3000 and switch pages at >2000 without causing issues like this? Indeed, if the entire 4 KiB block at >3000..>3FFF is unused by the p-system, using >3000 (SAMS register address = >4004) as your only 4 KiB paging address, you are good for a single 4 KiB SAMS page window. ...lee 2 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted March 29 Share Posted March 29 1 minute ago, Lee Stewart said: Indeed, if the entire 4 KiB block at >3000..>3FFF is unused by the p-system, using >3000 (SAMS register address = >4004) as your only 4 KiB paging address, you are good for a single 4 KiB SAMS page window. ...lee Now that we know that >3000..>3FFF is free that seems like the best solution to me. There are very few problems with just having one window for SAMS. The only time you need to think about it is if you want to copy from SAMS page to SAMS page. That will require reading some SAMS data into normal memory, change page and copy it back. I ran into this with the ED99 editor and ended up using two "windows" so I could copy records SAMS-to-SAMS with the most efficiency but it is a luxury in a tiny machine like 99. Not a necessity. 2 Quote Link to comment Share on other sites More sharing options...
+Vorticon Posted March 29 Share Posted March 29 3 hours ago, TheBF said: Now that we know that >3000..>3FFF is free that seems like the best solution to me. There are very few problems with just having one window for SAMS. It's not free, just not needed while running an assembly program, at least based on @apersson850's memory map. It will need to be restored prior to returning to the host program. Quote Link to comment Share on other sites More sharing options...
apersson850 Posted March 29 Author Share Posted March 29 (edited) The very end of it is not used by the p-system, I believe. I have not verified that. But as long as you return the original page prior to returning you can use other pages too. To implement a DSR which can act as a disk controller you don't need to worry about copying from one page to another. That's done in the same way as for a physical disk, i.e. read the data from the disk/SAMS to a buffer in RAM, write that buffer to disk/SAMS at a different place. Not as efficient as moving from one page to another directly, but the advantage is that it's all normal file handling. Some details: The p-system was from an early stage aimed at being easy to move to other computers. Hence it's a very layered system. Pretty far down in the layers is the RSP (Runtime Support Package). The RSP contains the various unit-procedures, like unitread and so on. The functions ioresult and time are there too. The RSP handles things like mapping device unit numbers, calculates the status of performed IO routines and similar. For this purposes the RSP uses the units globals, kernel and BIOS (Basic Input Output System). The next layer down, the unit BIOS also uses units globals and kernel, so they are on the same page about where other system data and services are located. In the BIOS all the generic unitread, unitwrite and similar are split up in unitread for console, unitread for serial port, unitread for disks and so on. Calculations to map the p-system's logical 512 byte disk block size to the physical sector size of the host computer are done on this level too. Reading a character from the keyboard is in this layer represented by picking a character from the input queue, but there is no actual keyboard access. All the way down here the system is written in Pascal. But from the BIOS calls are made to the SBIOS (Simplified Basic Input Output System). Down at the SBIOS layer we hit assembly language specifically written for the CPU and computer architecture the p-system is actually running on. In the 99/4A, parts of the SBIOS is executing from the p-code card ROM. Then it branches to parts stored in expansion RAM (2000-3FFFH part), where the p-code card can be turned off and an (almost) standard DSRCALL is done. This in not a complete DSRLINK, since the p-system at boot time does DSRPROBE calls, to figure out where the DSR code it will later use is located. When it has found the disk controller att boot time, it will create a PCB (Peripheral Control Block) which is a record with the CRU base address, entry address of the sector read/write procedure and a standard PAB for that kind of call. Later, when the SBIOS is calling the disk read/write sector DSR, it will no longer scan for anything. It will populate the PAB with the required information, link to it just like you do with the normal DSRLNK, then just enable the already known CRU address and branch to the already known DSR address. That last part of the sentence is the important thing here, because it means we can create a dummy PCB, plug in whatever CRU and branch address we like and then just populate the system's list of known devices with a link to this PCB and links to the system's already existing routines for the unit-procedures applicable to our faked device. In this particular case it should behave like a disk controller, so we copy the links for units that actually do access the disk controller, create a PAB in our PCB that's identical to the one used by the real disk controller and the only difference is the link to our dummy PCB, which will send the SBIOS into our DSR, which then doesn't even have to be on a card with memory in the normal DSR space. So not even the SBIOS will have to know that it's calling a DSR that's very much out of the ordinary. It will just follow it's normal path without even realizing it has been tricked into some very special DSR. In the particular case with the SAMS page we'll store that CRU address of the SAMS card, not because we need to (there's no DSR memory on the card), but because it saves us the work to enable/disable the card ourselves and then branch to a DSR doing the equivalent of sector read/write for our RAM-disk. This routine can most probably reside high up in the 2000-3FFFH block, since the very last part there isn't used by the p-system. At least so it seems. Using Classic 99, it's easy enough to fill that memory with some specific data and then verify that it hasn't been changed. To do this thing a few things have to be written. The DSR which simulates sector read/write from/to SAMS. The program which installs this code in memory, as it can't be loaded the normal way. A program which fills in the system's tables with the proper values. When I've done these things before, I've selected to keep these things separate. The reason is that loading the DSR has been completely separate from starting the system with my solutions, so once item 2 has been executed once, then as long as the computer has been powered I've only needed to do item 3, even if I've done a complete reboot of the p-system. Inside item 3 I've also included telling the system that the compiler, editor, filer, assembler and linker are on the RAM-disk. But that's not true the first time you execute it, since you need to create the RAM-disk before you can transfer these system programs to it. So you have to do item 3, then use the filer to zero the new RAM-disk device and then move the system files to it. After that, I do item 3 once again, and now it's true that the system files are on the RAM-disk, so after this the system will run them from there. Edited March 29 by apersson850 3 Quote Link to comment Share on other sites More sharing options...
+Vorticon Posted March 29 Share Posted March 29 1 hour ago, apersson850 said: But as long as you return the original page prior to returning you can use other pages too. I tried >A000 and the system crashed every time. Since there is no way to tell where in upper memory an assembly program is residing, it seemed safe to avoid upper memory altogether. 1 hour ago, apersson850 said: To do this thing a few things have to be written. The DSR which simulates sector read/write from/to SAMS. The program which installs this code in memory, as it can't be loaded the normal way. A program which fills in the system's tables with the proper values. When I've done these things before, I've selected to keep these things separate. The reason is that loading the DSR has been completely separate from starting the system with my solutions, so once item 2 has been executed once, then as long as the computer has been powered I've only needed to do item 3, even if I've done a complete reboot of the p-system. Inside item 3 I've also included telling the system that the compiler, editor, filer, assembler and linker are on the RAM-disk. But that's not true the first time you execute it, since you need to create the RAM-disk before you can transfer these system programs to it. So you have to do item 3, then use the filer to zero the new RAM-disk device and then move the system files to it. After that, I do item 3 once again, and now it's true that the system files are on the RAM-disk, so after this the system will run them from there. With all this needing to be done, particularly the invocation of the Filer and the copying of all the needed programs to the RAM disk, initial boot time must have been pretty lengthy (I'm estimating 2-3 minutes). A minor inconvenience I suppose in return for the benefits of a RAM disk. Seems to me you are best suited to make this project a reality since you've essentially done all this before. The only bit that would be different would be the windowing of the RAM access, and that's pretty straightforward to do as I've shown previously. What say you? 😁 Quote Link to comment Share on other sites More sharing options...
apersson850 Posted March 29 Author Share Posted March 29 (edited) Yes, the initial start takes a while. But since the system allows for input redirection, you can write a script that does all that automatically. Regarding the project then yes, I think I know most of what needs to be done. Right now I'm involved in the arrangement of three sports events, so there will be no programming the nearest month. Edited March 29 by apersson850 Quote Link to comment Share on other sites More sharing options...
+Vorticon Posted March 31 Share Posted March 31 I'm trying to get bitmap mode working under the p-system. I'm using @apersson850's bitreserve scheme to reserve the VDP memory for bitmap mode, then I'm setting up all the appropriate VDP registers and loading the pattern descriptor table and the color table with the appropriate data from an image on disk. Prior to reserving the VDP memory, I am copying the entire VDP RAM to the SAMS card for later restoration. I verified with the Classic99 debugger that all the VDP registers are properly set up and that the VDP data has been loaded correctly, but it seems that the system is refusing to switch to bitmap mode after setting VR0 appropriately (value of 2) and I'm getting garbage on the screen although the colors appear correct. I did save the modified registers to the PME table (not sure if that is necessary). I have attached a disk image of the code. Execute BITRESERVE to run the demo. Note that it does not restore the system properly afterward. I haven't gotten to that yet. Incidentally, I am quite familiar with bitmap mode and I've done this many times outside of the p-system, so I think there is some special set up I am missing here under this environment. Classic99 QI399.065 2024-03-31 09-13-45.mp4 Here is the modified bitreserve code: Spoiler (* reserve vdp memory for bitmap *) (* backs up entire vdp to sams card [pages 16 to 19] *) program bitreserve; {$U commandio.code} uses commandio; const intmem = 10112; { Interpreters VDP memory pointer } newint = 14360; { New intmem value } type byte = 0..255; dual = record case boolean of true :(int :integer); false:(ptr :^integer); end; (* dual *) var i, spage, size, offset, vdpadr : integer; vdparr : packed array[0..8191] of byte; function samsinit : integer; external; function samssize : integer; external; procedure dataops(rwcode : integer; var spage, size, offset : integer; var bytearr); external; procedure vmbr(address : integer; var bytearr; bytenum : integer); external; procedure poke(addr, value :integer); var window :dual; begin window.int := addr; window.ptr^ := value; end; (* poke *) begin i := samsinit; {initialize the sams card} writeln('sams card found and initialized'); i := samssize; {verify number of pages available} writeln(i, ' pages available'); spage := 16; offset := 0; size := sizeof(vdparr); vdpadr := 0; {back up vdp memory to sams card} for i := 1 to 2 do begin vmbr(vdpadr, vdparr, 8192); {read 8k of vdp} dataops(1, spage, size, offset, vdparr); {save in sams card} vdpadr := 8192; spage := 18; size := sizeof(vdparr); end; writeln('vdp memory backed up'); {reserve bitmap area in vdp} poke(intmem,newint); writeln('bitmap memory reserved'); writeln(chr(10), 'loading imagedemo'); chain('imagedemo'); end. (* bitreserve *) and here is the imagedemo program which attempts to put a bitmap image on screen. The SAMS and VDP utilities associated with it are below as well. Spoiler (* bitmap image demonstration *) program imagedemo; type byte = 0..255; dual = record case boolean of true :(int :integer); false:(ptr :^integer); end; (* dual *) var spage, bytenum, offset, vdpadr : integer; buffer : packed array[0..6143] of byte; function getkey : integer; external; procedure dataops(rwcode : integer; var spage, bytenum, offset : integer; var buffer); external; procedure vmbw(vdpadr : integer; var bytearray; bytenum : integer); external; procedure vsbw(vdpadr, byteval : integer); external; procedure vwtr(regnum, byteval : integer); external; procedure regcopy(regnum, regval : integer); external; procedure getimage(imagename : string); (* load image pattern and color files from disk into sams card *) var infile : file; pname, cname : string; blocks : integer; begin pname := concat(imagename, '.pdat'); cname := concat(imagename, '.cdat'); reset(infile, pname); {open pattern data file} blocks := blockread(infile, buffer, 12); {load pattern data} offset := 0; bytenum := sizeof(buffer); dataops(1, spage, bytenum, offset, buffer); {save pattern data to sams card} close(infile); reset(infile, cname); {open color data file} blocks := blockread(infile, buffer, 12); {load color data} offset := 2048; bytenum := sizeof(buffer); dataops(1, spage, bytenum, offset, buffer); {save color data to sams card} spage := succ(spage); close(infile); end; (* getimage *) procedure initbitmap; begin vwtr(7, 241); {set background color to black} regcopy(7, 241); {save register to pme vr table} vwtr(1, 224); {16k ram and vdp interrupts enabled} regcopy(1, 224); vwtr(2, 7); {sit address at >1c00} regcopy(2, 7); vwtr(3, 127); {ct address at >0000} regcopy(3, 127); vwtr(4, 7); {pdt address at >2000} regcopy(4, 7); vwtr(5, 62); {sal address at >1f00} regcopy(5, 62); vwtr(6, 3); {sdt address at >1800} regcopy(6, 3); vsbw(7936, 208); {mark start of sal as invalid} vwtr(0, 2); {initiate bitmap mode} end; (* initbitmap *) procedure showimage(spage : integer); begin offset := 0; bytenum := sizeof(buffer); dataops(2, spage, bytenum, offset, buffer); {load pattern data from sams} vmbw(8192, buffer, sizeof(buffer)); {transfer pattern data to vdp} offset := 2048; {point to color data in sams} bytenum := sizeof(buffer); dataops(2, spage, bytenum, offset, buffer); {load color data from sams} vmbw(0, buffer, sizeof(buffer)); {transfer color data to vdp} spage := succ(spage); end; (* showimage *) begin spage := 20; {start of image data in sams card} initbitmap; getimage('viger1'); showimage(20); repeat until getkey <> 255; end. (* imagedemo *) SAMS utilities: Spoiler ;routines for sams card access ;walid maalouli ;march 2024 .func samsinit ;initialize the sams card and verify card is present ;returns 0 for absent and 1 for present ;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 c r1,@401eh ;if match then card present jne nocard li r2,1 jmp endinit nocard clr r2 endinit mov r2,*r10 ;place card indicator on return stack sbz 0 ;turn sams card off bl @pcodeon mov @procret,r11 b *r11 pcodeon li r12,1f00h ;activate the pcode card sbo 0 mov @pmeret,r12 ;restore the pme pointer b *r11 pcodoff mov r12,@pmeret ;save the pme pointer li r12,1f00h ;deactivate the pcode card sbz 0 b *r11 pmeret .word procret .word .func samssize ;returns the number of pages available ;usage: sizeint := samssize .ref pcodeon,pcodoff,procret mov r11,@procret bl @pcodoff li r12,1e00h ;cru address of sams card sbo 0 ;turn on card sbo 1 ;turn mapping on li r4,16 ;page counter. skip over first 16 pages li r1,15 ;starting bank/page mov @2000h,r3 ;save contents of test memory location li r2,0ffffh ;test value mov r2,@2000h ;load test memory with value incpage ai r1,1 ;add page/bank starting at page >10 bank 0 swpb r1 mov r1,@4004h ;map address >2000 to page/bank c r2,@2000h ;did it write correctly? jeq endpage ;new page should not equal initial value swpb r1 inc r4 ;increment page counter jmp incpage ;try next page endpage li r1,0200h ;restore original mapping mov r1,@4004h mov r3,@2000h ;restore contents of test memory location sbz 1 ;turn mapping off sbz 0 ;turn off sams card mov r4,*r10 ;return page counter bl @pcodeon mov @procret,r11 b *r11 .proc dataops,5 ;read/save data to sams pages up to maximum card capacity ;usage: dataops(rwcode, startpage, datasize, offset, data) ;rwcode : 1=save, 2=read ;startpage is the starting page for the save operation. ;subsequent pages will be automatically assigned if needed ;datasize can be obtained by sizeof(data) ;offset is the number of bytes from the start of the page ;data is a packed array of byte .ref pcodeon,pcodoff,procret mov r11,@procret bl @pcodoff mov *r10+,r4 ;get pointer to data array mov *R10+,r3 ;get pointer to page offset mov *r10+,r2 ;get pointer to number of bytes to transfer mov *r10+,r1 ;get pointer to starting page li r6,4004h ;starting sams register (memory >2000) li r12,1e00h ;cru address of sams card sbo 0 ;turn card on li r5,2000h ;base memory address a *r3,r5 ;apply byte offset mov *r3,r0 ;store offset in byte counter at start mov *r10,r3 ;get r/w code sbo 1 ;turn mapper on nxtpage swpb *r1 mov *r1,*r6 ;assign page to sams register swpb *r1 rwops ci r3,1 ;is it a write operation? jne getops saveops mov *r4+,*r5+ ;save 2 bytes at a time (word) jmp contops getops mov *r5+,*r4+ ;get 2 bytes at a time contops dect *r2 jle opsdone ;no more data inct r0 ci r0,4096 ;are we past 4k of data? jlt rwops inc *r1 ;next page number clr r0 li r5,2000h jmp nxtpage ;continue data ops opsdone li r1,0200h ;restore sams register to original page mov r1,@4004h sbz 1 ;turn mapper off sbz 0 ;turn off sams card bl @pcodeon mov @procret,r11 b *r11 .end VDP utilities: Spoiler ;vdp access routines ;by walid maalouli ;march 2024 vdpwa .equ 8c02h ;vdp write address vdprd .equ 8800h ;vdp read data vdpwd .equ 8c00h ;vdp write data vrtab .equ 2810h ;pme vr table .proc vwtr,2 ;vdp write to register ;usage: vwtr(regnum, byteval) mov *r10+,r0 ;get the register value li r1,8000h ;bit mask for msb swpb *r10 ;r10 has pointer to register number socb r1,*r10 ;set the most significant bit swpb r0 movb r0,@vdpwa ;write byte value nop movb *r10,@vdpwa ;write the register number nop b *r11 .proc vsbr,2 ;vdp single byte read ;usage: vsbr(vdpadr, bytevar) mov *r10+,r0 ;get the pointer to the variable swpb *r10 ;r10 now has the vdp address movb *r10,@vdpwa ;write the vdp address lsb swpb *r10 movb *r10,@vdpwa ;write the vdp address msb nop movb @vdprd,*r0 ;store vdp byte into variable b *r11 .proc vmbr,3 ;vdp multiple byte read ;usage: vmbr(vdpadr, bytearray, bytenum) mov *r10+,r0 ;get the number of bytes to read mov *r10+,r1 ;get the pointer to the byte array swpb *r10 ;r10 now has the vdp address movb *r10,@vdpwa ;write the vdp address lsb swpb *r10 movb *r10,@vdpwa ;write the vdp address msb nop readnxt movb @vdprd,*r1+ ;read byte dec r0 jne readnxt ;done reading all bytes? b *r11 .proc vsbw,2 ;vdp single byte write ;usage: vsbw(vdpadr, intval) mov *r10+,r0 ;get the pointer to the variable swpb *r10 ;r10 now has the vdp address movb *r10,@vdpwa ;write the vdp address lsb swpb *r10 li r1,4000h ;bit mask for vdp address msb socb r1,*r10 ;set the 2 most significant bits movb *r10,@vdpwa ;write the vdp address msb swpb r0 movb r0,@vdpwd ;write byte to vdp address b *r11 .proc vmbw,3 ;vdp multiple byte write ;usage: vmbw(vdpadr, bytearray, bytenum) mov *r10+,r0 ;get the number of bytes to write mov *r10+,r1 ;get the pointer to the byte array swpb *r10 ;r10 now has the vdp address movb *r10,@vdpwa ;write the vdp address lsb swpb *r10 li r2,4000h ;bit mask for vdp address msb socb r2,*r10 ;set the 2 most significant bits movb *r10,@vdpwa ;write the vdp address msb wrinxt movb *r1+,@vdpwd ;write byte to vdp dec r0 jne wrinxt ;done writing all the bytes? b *r11 .proc regcopy,2 ;save copy of vdp register in pme table at >2810 ;usage: regcopy(regnum, byteval) mov *r10+,r0 ;get register value mov *r10,r1 ;get register value dec r1 ;calculate vr address in table sla r1,1 ai r1,vrtab movb r0,*r1 ;save vr value in table b *r11 .end SAMSUTIL.dsk 2 Quote Link to comment Share on other sites More sharing options...
+Vorticon Posted March 31 Share Posted March 31 False alarm... I had forgotten to initialize the SIT... I'll post the complete demo in a day or two. Viger! 2 Quote Link to comment Share on other sites More sharing options...
+Vorticon Posted April 1 Share Posted April 1 OK everything works as it should now. The p-system was never intended to be used in bitmap mode, so credit goes to @apersson850 for figuring out how to coerce it to do so. Only issue is getting the keyboard key capture working while in bitmap mode. I'll have to study @apersson850's Turtle unit to see how he did it. Classic99 QI399.065 2024-03-31 21-37-37.mp4 SAMSUTIL.dsk 8 Quote Link to comment Share on other sites More sharing options...
gferluga Posted April 1 Share Posted April 1 I'm using MAME but probably I'm doing something wrong. If I kick <E> or <R> is complaining about missing compiler or editor. This is my command lone for execution: ./mame ti99_4a -window -nomouse -skip_gameinfo -autoframeskip -natural -ioport peb -ioport:peb:slot2 32kmem -ioport:peb:slot3 tirs232 -ioport:peb:slot4 pcode -ioport:peb:slot8 tifdc -flop1 "software/ti99_4a/disks/SAMSUTIL.dsk" Thanks! 1 Quote Link to comment Share on other sites More sharing options...
+mizapf Posted April 1 Share Posted April 1 TIImageTool says that this disk image has 80 tracks. This may fail with the standard 5.25" drives in MAME; maybe try a 3.5" drive. Or copy the contents to a 40 track image. Quote Link to comment Share on other sites More sharing options...
+Vorticon Posted April 1 Share Posted April 1 1 hour ago, gferluga said: I'm using MAME but probably I'm doing something wrong. If I kick <E> or <R> is complaining about missing compiler or editor. This is my command lone for execution: ./mame ti99_4a -window -nomouse -skip_gameinfo -autoframeskip -natural -ioport peb -ioport:peb:slot2 32kmem -ioport:peb:slot3 tirs232 -ioport:peb:slot4 pcode -ioport:peb:slot8 tifdc -flop1 "software/ti99_4a/disks/SAMSUTIL.dsk" Thanks! The editor/filer, compiler, and assembler/linker are all separate disks. I have attached all the system disks you need for the p-system. The Editor/Compiler disk needs to be inserted in one of the drives in addition to SAMSUTIL if you want to view/edit or run files from the latter. ASM-LNK.DSK EDITOR-COM.dsk UCSD-UTI.DSK 1 1 Quote Link to comment Share on other sites More sharing options...
+Vorticon Posted April 1 Share Posted April 1 5 minutes ago, mizapf said: TIImageTool says that this disk image has 80 tracks. This won't work with the standard 5.25" drives in MAME; maybe try a 3.5" drive. Or copy the contents to a 40 track image. It's not. I have a standard 40 track TIFDC on my system. Quote Link to comment Share on other sites More sharing options...
+mizapf Posted April 1 Share Posted April 1 I just tried, and it seems as if the disk system in MAME interprets the 180K disk as 40 tracks, overriding the information in the Volume Information Block. 00000000: 5341 4d53 5554 494c 2020 02d0 0944 534b SAMSUTIL ...DSK 00000010: 2050 0201 0000 0000 0000 0000 0000 0000 P.............. 00000020: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000030: 0000 0000 0000 0000 ffff ffff ffff ffff ................ 00000040: ffff ffff ffff ffff ffff ffff ffff ffff ................ 00000050: ffff ffff ffff ffff ffff ffff ffff ffff ................ 00000060: ffff ffff ffff ffff ffff ffff ffff ffff ................ 00000070: ffff ffff ffff ffff ffff ffff ffff ffff ................ 00000080: ffff ffff ffff ffff ffff ffff ffff ffff ................ 00000090: ffff ffff ffff ffff ffff ffff ffff ffff ................ The 0x50 value at 0x00000011 means 80 tracks in the standard TI file system. For 40 tracks, this should be 0x28. Maybe in Pascal this value is ignored. Quote Link to comment Share on other sites More sharing options...
+Vorticon Posted April 1 Share Posted April 1 Quite possibly. Add it to the list of quirks and features of the p-system 😀 Quote Link to comment Share on other sites More sharing options...
gferluga Posted April 1 Share Posted April 1 Looks like SAMS card is not available in Mame 🤔 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.