marc.hull Posted June 14, 2018 Share Posted June 14, 2018 Does anyone know or have a tutorial on how to control the SAMS card with software ? Not interested in the hardware aspects just in how to manipulate them. 1 Quote Link to comment Share on other sites More sharing options...
Omega-TI Posted June 14, 2018 Share Posted June 14, 2018 Does anyone know or have a tutorial on how to control the SAMS card with software? That is a damn good question! Quote Link to comment Share on other sites More sharing options...
+adamantyr Posted June 14, 2018 Share Posted June 14, 2018 The TI Tech pages has some examples, but they aren't as clear and concise as they could be. I could write something up for it, since I had to hash my way through it. 5 Quote Link to comment Share on other sites More sharing options...
+Vorticon Posted June 14, 2018 Share Posted June 14, 2018 The TI Tech pages has some examples, but they aren't as clear and concise as they could be. I could write something up for it, since I had to hash my way through it. That would be great! Definitely an underutilized gem of hardware bit... Quote Link to comment Share on other sites More sharing options...
+mizapf Posted June 14, 2018 Share Posted June 14, 2018 SAMS as implemented in MAME: https://github.com/mamedev/mame/blob/master/src/devices/bus/ti99/peb/samsmem.cpp In short, if you don't like to read cpp code: There are two CRU bits (1E00 and 1E02); the first one allows access to the mapper, the second enables mapping (otherwise the memory locations are the logical addresses as issued on the address bus). When the mapper access is enabled, memory locations 4000,4002,4004,...401e can be loaded with a byte value that represents the bank number. The 16 slots of the mapper represent the 16 pages of 4K in the address space (0000, 2000, ..., E000). Only the logical addresses 2000-3FFF and A000-FFFF are used. Thus, the mapper has a lot of unused positions; only 4004,4006,4014,4016,4018,401a,401c,401e have an effect. The SAMS can be equipped with 1 MiB (two 512K RAMs). This allows for 256 pages of 4K, numbered from 00 to FF. By loading the page number into the mapper, it shows up in the respective area. Due to a lack of test software, I think I never really tested it throughly. Maybe someone would like to try with this information? 1 Quote Link to comment Share on other sites More sharing options...
+InsaneMultitasker Posted June 14, 2018 Share Posted June 14, 2018 I seem to recall that Bruce Harrison wrote some good introductory info in a Micropendium Art of Assembly column. Quote Link to comment Share on other sites More sharing options...
atrax27407 Posted June 14, 2018 Share Posted June 14, 2018 Also check the TurboForth site. Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted June 14, 2018 Share Posted June 14, 2018 I seem to recall that Bruce Harrison wrote some good introductory info in a Micropendium Art of Assembly column. Yeah—He discussed it in Parts 77, 78 and 80. Those parts were submitted to Micropendium but never published. A PDF of Harrison’s “Art of Assembly” columns is available at WHTech. ...lee 1 Quote Link to comment Share on other sites More sharing options...
+jedimatt42 Posted June 14, 2018 Share Posted June 14, 2018 The Geneve section of WHTECH is full of good stuff too... Cause??? ( just like most of the DSK files are under videos... ) I was just browsing and spotted this: ---------------------------------------- AAAA M M SSSSS A A MM MM S A A M MM M S AAAAAA M M SSSS A A M M S A A M M S A A M M SSSSS ---------------------------------------- Programmer's Documentation Documention: 1/19/93 Joe Delekto Note: This documentation covers the 128k AMS system only. After the AEMS is released, documentation will be available. ---------------------------------------- The AMS expanded memory card is a unique piece of hardware, in that mapping is simple, and lends itself well to overlay-structured programming. Because of the AMS design, no memory manager is necessary. The card itself uses a 17 bit address bus (18 for 512k) in order to access the SRAM on the card. The upper 4 bits of a standard 16 bit address are used to select one of 16 mapper registers. The remaining 12 bits from the address bus are combined with 12 bits taken from the mapper register, in order to give a maximum address bus of 24 bits in width. This will allow for a maximum of 16MB to be accessed. (AEMS) On the 128k card, only the 5 least significant bits (6 for 512k) are used from the mapper register. The other pins from the mapper output are unconnected. "Mapping" is accomplished by changing the value in the mapper register, to point to one of 32 pages (64 on 512k). No reading/writing or any transfer of memory is involved with mapping. All that is changed is the pointer to the RAM chip on the address bus. Because of this, mapping can be done in a few clock cycles, using only a couple of instructions. Programs which take advantage of the AMS can be extremely large, with about no change in execution time. As with any memory expansion, there are limitations on overlay sizes. It is recommended for the AMS system, that the root segment of your program be placed in low memory. (>2000 - >3FFF) Code overlays, from 4k to 24k in size, (in 4k increments) can be mapped in within the upper 24k of memory. This means that an 8k root segment can call as many (up to 24k) overlays as necessary. The result is a HUGE program, with structure and modularity. (Most desired in the programming field!) This document will describe how mapping works, as well as the AMS resident library created by Art Green and myself. I will also go into some detail as to how you can use Charles Earl's Hot Bug debugger to debug AMS code. Before I get to the meat of this document, I would like to explain why we chose our method of memory expansion. We chose 4k pages for two reasons. First, it made the hardware design simple, and made utility routines short and fast. Second of all, since our system uses overlay methods, many 4k overlays can reside in memory at once. The overlays can be any size from 4k to 24k in length, falling on 4k page boundaries. The larger the overlay is, the less overlays you can have. You can have 4k, 8k, 12k, 16k, or 24k overlays, and overlay size determines how many overlays you can have. (i.e. Six 4k, three 8k, etc.) You are NOT required to use only one size of overlay. For instance, you could have one 12k overlay, and an 8k overlay, along with a 4k overlay. (24k total). Keep in mind that most subroutines fall well under 4k of space! This means that MANY subroutines can be placed within just one 4k overlay! We believe you will find this to be one of the most flexible memory expansion systems, ever to be designed for the TI-99/4A. Many interesting applications, besides large programs, can be developed. We are making all information on the use of the memory available, so that programmers can make full use of its abilities. ---------------------------------------- PART ONE: Map Modes and Registers ================================== Because the AMS has a 17 bit address bus, (18 for 512k) and the TI-99/4A only has a 16-bit address bus, the extra bit(s) need to come from somewhere. These extra bits are taken from the mapper registers. 4 bits are taken from the memory address on the 9900 bus, and used to select one of 16 mapper registers. The remaining 12 bits from the 9900 bus are combined with the 5 bits from the mapper register, to make a new bus with 17 bits. The actual paging process is done by changing the values in the mapper registers, to point to new pages in memory. Here is the address diagram: * From 9900 Address bus: >A000 |+-- || |+---> 12 MSB to 12 LSB of new address | +----> 4 MSB to mapper register select * From mapper 5 bit output forms 5 MSB of new address A15 - Mapper Register Select A14 - " " " " " " A13 - " " " " " " A12 - " " " " " " Mapper Address Bus A11 - MA11 A10 - MA10 A09 - MA09 A08 - MA08 A07 - MA07 A06 - MA06 A05 - MA05 A04 - MA04 A03 - MA03 A02 - MA02 A01 - MA01 A00 - MA00 * On Mapper Address bus: +---+ A15 -| M |- MA16 A14 -| a |- MA15 A13 -| p |- MA14 A12 -| p |- MA13 | e |- MA12 | r | +---+ Since only the >A000 - >F000 range inside memory is mapped, register >A through >F are used in the mapper. Note the mapper register number corresponds with the 4 MSB of the address being accessed. Once the mapper register is loaded with a page number, (5 bit address which forms 5 MSB on AMS bus) any read or write to the 4k block it corresponds to, will access that 4k memory page. For example: I load mapper register 10 (>A) with page number >15. Any time I read/write or access the >A000 block, I will be writing to the 4k page >15. If I were to load mapper register 10 with >15, then perform a CLR @>A02E, I will actually be writing (from the AMS address bus) the address: >0001502E. Notice how the page/offset are combined on the AMS bus to get a 17 bit address (show here as 32 bits for clarity). It will be worthwile to note, that even though the address was >A000, the >A had no influence whatsoever on the new address. The primary purpose of the >A was to select which mapper register the 5 bits will come from. The same holds true for the entire >A000 - >FFFF range. Because >A - >F are used to select the mapper registers, we have 6 registers to use, and 6 4k boundaries. To load consecutive addresses, just load the consecutive page numbers into the mapper registers. The AMS system works in two modes. map mode, and pass mode. Power-up places AMS into pass mode. When the mode is in pass, AMS acts as a plain 32k card, and the mapper passes actual addresses used to the AMS bus. (i.e. a CLR @>A000 will clear the memory location at >A000). There is no difference between pass mode, and standard 32k mode. The second mode is map mode. Map mode is the mode which uses the MSB of an address to select the mapper register, then dump the register's contents to the AMS bus. Note, when map mode is enabled, it would be a good idea to initialize the mapper registers to known values! The CRU address for AMS is >1E00. In order to use mapping, some CRU instructions are required to: 1) Switch AMS between map/pass modes, and 2) enable/disable register read/writes. Below is the code which changes map modes for AMS. LI R12,>1E00 * AMS CRU Address SBO 1 * Enable Mapping SBZ 1 * Disable Mapping This is the only code required to switch back between modes. Only 2 instructions are necessary. In order to access the mapper registers, CRU bit 0 must be set. When it is, DSR space is temporarily disable, so that writing in the >4000 space will set a map register. When CRU bit 0 is set to zero, original DSR space is recovered, with no side effects. It is recommended that you enable mapper registers, write their values, and then disable them immediately. The reason being that forgetting to disable the registers will keep you from accessing and DSR routines. To enable and disable registers, use the following code: LI R12,>1E00 * AMS CRU address SBO 0 * Enable Registers . . * Set registers here . SBZ 0 * Disable Registers In order to load a mapper register with a page number, all you need to do is write to the >4000 block. To determine which mapper register you wish to change, use the follow calculation: MRAD = 2 * Register# + >4000 So that to clear mapper register 10, you would use: 2 * >A + >4000 = >4014 CLR @>4014 * Clear Register 10 Note, you can also read from a mapper register, for the purpose of saving previous page values: SPAGE BSS 2 * Hold Page # EXMPL MOV @>4014,@SPAGE * Get MR10 CLR @>4014 * Clear MR10 . . . MOV @SPAGE,@>4014 * Restore Page RT Because writing to the mapper registers is just writing to an address, indirect addressing could be used as well. For example, Consider setting up the mapper so that when in map mode, addresses are the same as in pass mode. It is always a good idea to first set up the mapper registers, and then go into map mode. While in map mode, registers can be changed at will to point elsewhere. If your code to do mapping resides in upper memory, take care NOT to change the register where your code is executing. Pointing to some other place in memory will continue execution on the new page, causing undesired, or unknown results. It is possible though, to point to a new page where code is executing, provided that valid code exists at the current offset and new page. Below is an example which sets up the mapper registers as normal 32k pass mode, yet places the mapper into map mode. The registers can be changed later to access other pages of memory. PAGES DATA >0A00,>0B00,>0C00 DATA >0D00,>0E00,>0F00 START LI R12,>1E00 * AMS CRU LI R1,PAGES * Page Table LI R2,>4014 * Start at MR >A LI R3,6 * 6 Pages to set SBO 0 * Enable MR's RSET MOV *1+,*2+ * Write to MR DEC R3 * Dec counter JNE RSET * Continue SBZ 0 * Disable MR's SBO 1 * Enable map mode END IMPORTANT: Note that the 5 bit page value is placed in the most significant byte of the mapper register. Because only 5 bits are used in a map register, and because the 2 cycle read/write on the data bus loads the most significant byte last, the mapper is loaded with this value. Therefore, page >18 would be >1800, page >05 would be >0500, etc. It might be worthwhile that AEMS addresses page numbers normally, since 12 bits are used instead. ---------------------------------------- PART TWO: Overlay Techniques ============================ Because the AMS system is able to map overlays up to 24k in length, on 4k boundaries, it lends itself well to program development using overlays. First, a root segment is established, which will contain the code to call an overlay. The root segment must remain in memory (without using tricky code to map it out), and will contain the routine used to call an overlay subprogram. We recommend the following: 1) Place the root segment into low memory (8k). 2) Make all overlay calls BLWP routines. Below is the stub code for both the root segment overlay manager, which is used to handle the simulation of a BLWP vector for a mapped environment. **************************************** * Overlay Manager * Version 1.0 * R.A.Green OVMGR SBO 0 * Enable map regs MOV *R11+,R10 * Get N # pages MOV *R11+,R9 * Get 1st map reg MOV *R11+,R7 * Get 1st page # OMGR2 MOV R7,*R9+ * Set mapper reg AI 7,>0100 * Add 1 to page # DEC R10 * Loop for N pages JGT OMGR2 * Finish loop SBZ 0 * Disable map regs MOV *R11,*R11 * Get real BLWP vec MOV *R11+,R7 * Get WSP MOV *11,R9 * Get sub address MOV R13,@26(R7) * Simulate BLWP MOV R14,@28(R7) * MOV R15,@30(R7) * OMGRW EQU $-12 * OVMGR workspace LWPI 0 * R6,R7 user wrkspc B @0 * R8,R9 call sub BSS 2 * R10 BSS 2 * R11 DATA >1E00 * R12 AMS CRU addr BSS 6 * R13 - R15 **************************************** Below is the code which replaces the original BLWP call in the root segment. This is done for every subroutine that generates an overlay. * Overlay Call * Version 1.0 * R.A.Green * BLWP @OSUB OSUB DATA OMGRW * Manager WSP DATA $+2 * BL @OVMGR * Use overlay manager DATA N * # Pages in overlay DATA >40xx * 1st mapper reg addr DATA n * 1st page number DATA sub * REAL BLWP vector **************************************** In order to generate a call for an overlayed subroutine, the real BLWP call must be replaced by the OSUB information. Now, the overlay generator needs to know: 1) How many pages the overlay is. Remember that it can be 4k-24k in length, broken into 4k pages. The routine needs to know what mapper registers to start mapping the 'N' pages in at. The first page number the overlay resides on is also given, along with the ACTUAL BLWP vector address for the overlayed routine. To illustrate this, let us say our root segment is in the >2000 - >3FFF block. We have created an overlay, and inside the overlay is a routine called INPUT, for which the BLWP vector starts at >C2E0. The overlay is in page >18 of memory, and is only 4k, or 1 page in length. To call the overlay, we would use the following code: BLWP @OSUB1 * Call overlay stub DATA >0001 * 1 page long (4k block) DATA >4018 * >C000 block DATA >1800 * 1st page # (only one) DATA >C2E0 * BLWP Vector Note, it would be very useful to have a program loader to load segments of code into different pages. Although such a loader exists for AMS, it is only used for AMS files with special headers for overlay and root segments. A similair loader can be constructed, which loads the overlays into their corresponding pages. The overlay code examples above, are the code segments installed (automatically) by the linker. That eliminates the need for passing the arguments to the overlay generator, and keeping track of relative page addresses. You may however, choose your own method of overlaying. We made it very flexible to customize your software so you can choose how you want to map. Keep in mind that other programs may be resident to AMS, and using the linker/loader will ensure that AMS programs are page relocatable, and won't overwrite memory resident code. ---------------------------------------- PART THREE: Using Hot Bug with AMS ================================== Most often overlay programs are tedious to debug. If you have access to Charles Earl's Hot Bug debugger, I recommend you learn how to use it. It is by far one of the best debugging utilities available, and can certainly work well for debugging AMS programs. Since Hot Bug will also load program files, you can use the debugger to change the page map, and load in your overlay code! Hot Bug Command Summary ER - Edit Register EW - Edit Word DM - Display Memory SPC - Set Program Counter G - Go (# of steps) In order to access the registers, and check the code/data within pages, we need to enable both the mapper, and the registers. Choose a word of memory that does not have code to use the following commands: (For this example, I use >3FF0) 1: ER 12 1E00 2: EW 3FF0 1D00 3: EW 3FF2 1D01 4: SPC 3FF0 5: G 2 (1: Load Register 12 with CRU >1E00) (2: Put SBO 0 at 3FF0 Enable REGS ) (3: Put SBO 1 at 3FF2 MAP Mode ) (4: Set program counter to >3FF0 ) (5: Execute 2 instructions ) NOTE: If the mapper is in an unknown state, (register values unknown), you will want to set the registers before actually placing into map mode. Just use G 1 instead, edit the registers (see below) and then G 1 again to get into map mode. To read/write to the mapper registers, use the DM command to look at the >4000 block. Only addresses >4000 - >4020 are of interest to us. (Mapper regs 0 - 16). NOTE: Even though the upper 24k is mapped using mapper registers 10 - 16, the other mapper registers can be used for temporary storage. 1: DM 4000 (1: Display Memory at >4000) In order to change a register value, just use the EW command. For example, to load mapper register 11, (>B000 block) with page >15, use the following: 1: EW 4016 1500 (1: Load mapper register 11 with >15) Now let's try an experiment. What we will do is write the same page to 2 different mapper registers, and observe what happens. Use the following commands: 1: EW 4014 1500 2: EW 4016 1500 3: DM A000 (1: Load mapper register 10 with >15) (2: Load mapper register 11 with >15) (3: Display memory at >A000 ) Note what the data in memory is at >A000. Now, if you use DM B000, you should see the same data you saw before. Let's try something interesting. Use the following commands: 1: EW A000 FACE 2: DM B000 (1: Put value >FACE into >A000) (2: Display memory at >B000 ) When you use the DM B000, you should get a surprise. When you wrote to A000, you actually changed the word at B000, as well as A000. Why? Because both 4k block point to the same page! Perhaps now you can envision some of the interesting tricks you can accomplish with the AMS system. One such application is the arbitrary locating of data buffers! It is also possible to load a memory image file, on non-consecutive pages, and yet still load the mapper registers such that the program is contiguous in the upper 24k! If that's so, then it means we can load E/A option 5 program files anywhere inside AMS, and then just map in their pages to the proper blocks in high memory! In this manner, even code with absolute origins becomes page relocatable, at least for paging purposes. By placing page numbers into the registers, and using Hot Bug's LOAD command, you can load overlay image files. Keep track of the address for the BLWP vector in the overlay, as well as the page you LOAD it into, and how many pages it takes up. This information you will need to pass to the overlay generator in your program. See? Loading, debugging, and running overlay code on the AMS system is very feasible, and not difficult. ---------------------------------------- This concludes this section of programmer's documentation. The next document will focus on the memory resident utility routines, which AMS programmers can use in their software. Memory allocation, exit code, memory moves, and far VDP read/write routines are available. Also, AMS program have access to the E/A 5, and AMS Overlay program file loader. The loader will load either type of file. The exit routines for AMS have the option of keeping the programmer's code resident for instant execution when desired. We have worked very hard for the past couple of years, to make this memory expansion as user friendly as possible. We are, and will continue to supply support for the AMS card. Without the software support to use AMS, it would just be an expensive paperweight. <<< Joe Delekto >>> 4 Quote Link to comment Share on other sites More sharing options...
RXB Posted June 14, 2018 Share Posted June 14, 2018 Does anyone know or have a tutorial on how to control the SAMS card with software ? Not interested in the hardware aspects just in how to manipulate them. I have a solution easy to control built into RXB. 2 Quote Link to comment Share on other sites More sharing options...
+adamantyr Posted June 14, 2018 Share Posted June 14, 2018 So here is what I do in my CRPG with the card, which I think should illustrate a 'hands on' approach: When you're in memory mapping mode, all your memory is in "pages" so it's actually pretty easy to accidentally break a program you just started in when turning it on. In the loader program, I set up pages 0-15 in the respective memory addresses, which appears to allow a smooth transition to mapping mode. I don't know how completely necessary this is, but it's best to assume the card is not initialized. * Set up AMS LI R12,>1E00 * Set CRU for AMS LI R0,>4000 CLR R1 LI R2,16 INIT1 SBO 0 * Turn on AMS card page mapping MOV R1,*R0+ * Copy page assignments (0-15) AI R1,>0100 * Add 1 to each page value DEC R2 JNE INIT1 * Are we at end of loop? SBZ 0 * Turn off memory page mode LI R12,>1E00 * Set CRU for AMS SBO 1 * Turn on mapping mode After loading all my program data into various pages in the loader, I set up half of the upper 24k to a fixed "root" module, which is always present, and the second half to a "start" module which has the title screen, music, character creation, etc. * Setup root segment, branch to start segment INIT3 LI R12,>1E00 * Access AMS card mapper SBO 0 LI R5,>0A0A * Set R5 to 10 (high byte) MOV R5,@>4014 * Set >A000 page for Root segment AI R5,>0100 * Add 1 to page MOV R5,@>4016 * Set >B000 page for next file AI R5,>0100 * Add 1 to page MOV R5,@>4018 * Set >C000 page for next file LI R5,>1600 * Set R5 to 22 (high byte) MOV R5,@>401A * Set >D000 page for Start segment AI R5,>0100 * Add 1 to page MOV R5,@>401C * Set >E000 page for next file AI R5,>0100 * Add 1 to page MOV R5,@>401E * Set >F000 page for next file AI R5,>0100 * Add 1 to page SBZ 0 B @>D000 * Branch to start segment In my actual program, I use the lower 8K as data pages, which are frequently switched. I wrote two calling routines called PAGE1 and PAGE2 which set the active page to the passed value. * Page swap routines. Page is stored in R3 * Page swap into >2000 PAGE1 DATA WS2,PAGE1A PAGE1A LI R0,>4004 * Set to >2000 page JMP PAGE PAGE2 DATA WS2,PAGE2A * Page swap into >3000 PAGE2A LI R0,>4006 * Set to >3000 page PAGE MOV @>0006(R13),R1 * Copy page value to bottom byte MOVB @>0007(R13),R1 * Copy page value to top byte LI R12,>1E00 SBO 0 * Access the mapper MOV R1,*R0 * Set the page number SBZ 0 RTWP The other part is the module switcher, which switches the high 12k page for travel, combat, and management modes. * Module swap. Current game mode in GSTATE SETMOD LI R12,>1E00 MOV @GSTATE,R0 JEQ SETTRV CI R0,1 JEQ SETMGR CI R0,2 JEQ SETCOM * Set start module LI R1,>1616 JMP SETMD2 * Set combat module SETCOM LI R1,>1313 JMP SETMD2 * Set travel module SETTRV LI R1,>0D0D JMP SETMD2 * Set manager module SETMGR LI R1,>1010 SETMD2 SBO 0 LI R0,>401A MOV R1,*R0+ AI R1,>0101 MOV R1,*R0+ AI R1,>0101 MOV R1,*R0+ SBZ 0 B @>D000 * Branch to start of module 3 Quote Link to comment Share on other sites More sharing options...
FDOS Posted June 14, 2018 Share Posted June 14, 2018 I, too, have easy to use solution in X4th99 and TI Basic Plus (TIB+). Neither have been released as I'm concentrating on TIB+ (due to TBforth & FBforth) and I keep adding and changing things in order to support all the new hardware being developed for the TI. 2 Quote Link to comment Share on other sites More sharing options...
+Schmitzi Posted June 14, 2018 Share Posted June 14, 2018 I also found this: A-look-at-the-SAMS-card---by-Shawn-Baron.pdf 1 Quote Link to comment Share on other sites More sharing options...
+Schmitzi Posted June 14, 2018 Share Posted June 14, 2018 and that: mp960910-Page22-25.pdf 1 Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted June 14, 2018 Share Posted June 14, 2018 SAMS is pretty simple in fbForth 2.0—almost the same as TurboForth, from which I ported it. Here are the relevant Forth words ( >MAP S0&TIB! SAMS! SAMS? ) from the manual: ...lee 2 Quote Link to comment Share on other sites More sharing options...
marc.hull Posted June 14, 2018 Author Share Posted June 14, 2018 The Geneve section of WHTECH is full of good stuff too... Cause??? ( just like most of the DSK files are under videos... ) I was just browsing and spotted this: ---------------------------------------- AAAA M M SSSSS A A MM MM S A A M MM M S AAAAAA M M SSSS A A M M S A A M M S A A M M SSSSS ---------------------------------------- Programmer's Documentation Documention: 1/19/93 Joe Delekto Note: This documentation covers the 128k AMS system only. After the AEMS is released, documentation will be available. ---------------------------------------- The AMS expanded memory card is a unique piece of hardware, in that mapping is simple, and lends itself well to overlay-structured programming. Because of the AMS design, no memory manager is necessary. The card itself uses a 17 bit address bus (18 for 512k) in order to access the SRAM on the card. The upper 4 bits of a standard 16 bit address are used to select one of 16 mapper registers. The remaining 12 bits from the address bus are combined with 12 bits taken from the mapper register, in order to give a maximum address bus of 24 bits in width. This will allow for a maximum of 16MB to be accessed. (AEMS) On the 128k card, only the 5 least significant bits (6 for 512k) are used from the mapper register. The other pins from the mapper output are unconnected. "Mapping" is accomplished by changing the value in the mapper register, to point to one of 32 pages (64 on 512k). No reading/writing or any transfer of memory is involved with mapping. All that is changed is the pointer to the RAM chip on the address bus. Because of this, mapping can be done in a few clock cycles, using only a couple of instructions. Programs which take advantage of the AMS can be extremely large, with about no change in execution time. As with any memory expansion, there are limitations on overlay sizes. It is recommended for the AMS system, that the root segment of your program be placed in low memory. (>2000 - >3FFF) Code overlays, from 4k to 24k in size, (in 4k increments) can be mapped in within the upper 24k of memory. This means that an 8k root segment can call as many (up to 24k) overlays as necessary. The result is a HUGE program, with structure and modularity. (Most desired in the programming field!) This document will describe how mapping works, as well as the AMS resident library created by Art Green and myself. I will also go into some detail as to how you can use Charles Earl's Hot Bug debugger to debug AMS code. Before I get to the meat of this document, I would like to explain why we chose our method of memory expansion. We chose 4k pages for two reasons. First, it made the hardware design simple, and made utility routines short and fast. Second of all, since our system uses overlay methods, many 4k overlays can reside in memory at once. The overlays can be any size from 4k to 24k in length, falling on 4k page boundaries. The larger the overlay is, the less overlays you can have. You can have 4k, 8k, 12k, 16k, or 24k overlays, and overlay size determines how many overlays you can have. (i.e. Six 4k, three 8k, etc.) You are NOT required to use only one size of overlay. For instance, you could have one 12k overlay, and an 8k overlay, along with a 4k overlay. (24k total). Keep in mind that most subroutines fall well under 4k of space! This means that MANY subroutines can be placed within just one 4k overlay! We believe you will find this to be one of the most flexible memory expansion systems, ever to be designed for the TI-99/4A. Many interesting applications, besides large programs, can be developed. We are making all information on the use of the memory available, so that programmers can make full use of its abilities. ---------------------------------------- PART ONE: Map Modes and Registers ================================== Because the AMS has a 17 bit address bus, (18 for 512k) and the TI-99/4A only has a 16-bit address bus, the extra bit(s) need to come from somewhere. These extra bits are taken from the mapper registers. 4 bits are taken from the memory address on the 9900 bus, and used to select one of 16 mapper registers. The remaining 12 bits from the 9900 bus are combined with the 5 bits from the mapper register, to make a new bus with 17 bits. The actual paging process is done by changing the values in the mapper registers, to point to new pages in memory. Here is the address diagram: * From 9900 Address bus: >A000 |+-- || |+---> 12 MSB to 12 LSB of new address | +----> 4 MSB to mapper register select * From mapper 5 bit output forms 5 MSB of new address A15 - Mapper Register Select A14 - " " " " " " A13 - " " " " " " A12 - " " " " " " Mapper Address Bus A11 - MA11 A10 - MA10 A09 - MA09 A08 - MA08 A07 - MA07 A06 - MA06 A05 - MA05 A04 - MA04 A03 - MA03 A02 - MA02 A01 - MA01 A00 - MA00 * On Mapper Address bus: +---+ A15 -| M |- MA16 A14 -| a |- MA15 A13 -| p |- MA14 A12 -| p |- MA13 | e |- MA12 | r | +---+ Since only the >A000 - >F000 range inside memory is mapped, register >A through >F are used in the mapper. Note the mapper register number corresponds with the 4 MSB of the address being accessed. Once the mapper register is loaded with a page number, (5 bit address which forms 5 MSB on AMS bus) any read or write to the 4k block it corresponds to, will access that 4k memory page. For example: I load mapper register 10 (>A) with page number >15. Any time I read/write or access the >A000 block, I will be writing to the 4k page >15. If I were to load mapper register 10 with >15, then perform a CLR @>A02E, I will actually be writing (from the AMS address bus) the address: >0001502E. Notice how the page/offset are combined on the AMS bus to get a 17 bit address (show here as 32 bits for clarity). It will be worthwile to note, that even though the address was >A000, the >A had no influence whatsoever on the new address. The primary purpose of the >A was to select which mapper register the 5 bits will come from. The same holds true for the entire >A000 - >FFFF range. Because >A - >F are used to select the mapper registers, we have 6 registers to use, and 6 4k boundaries. To load consecutive addresses, just load the consecutive page numbers into the mapper registers. The AMS system works in two modes. map mode, and pass mode. Power-up places AMS into pass mode. When the mode is in pass, AMS acts as a plain 32k card, and the mapper passes actual addresses used to the AMS bus. (i.e. a CLR @>A000 will clear the memory location at >A000). There is no difference between pass mode, and standard 32k mode. The second mode is map mode. Map mode is the mode which uses the MSB of an address to select the mapper register, then dump the register's contents to the AMS bus. Note, when map mode is enabled, it would be a good idea to initialize the mapper registers to known values! The CRU address for AMS is >1E00. In order to use mapping, some CRU instructions are required to: 1) Switch AMS between map/pass modes, and 2) enable/disable register read/writes. Below is the code which changes map modes for AMS. LI R12,>1E00 * AMS CRU Address SBO 1 * Enable Mapping SBZ 1 * Disable Mapping This is the only code required to switch back between modes. Only 2 instructions are necessary. In order to access the mapper registers, CRU bit 0 must be set. When it is, DSR space is temporarily disable, so that writing in the >4000 space will set a map register. When CRU bit 0 is set to zero, original DSR space is recovered, with no side effects. It is recommended that you enable mapper registers, write their values, and then disable them immediately. The reason being that forgetting to disable the registers will keep you from accessing and DSR routines. To enable and disable registers, use the following code: LI R12,>1E00 * AMS CRU address SBO 0 * Enable Registers . . * Set registers here . SBZ 0 * Disable Registers In order to load a mapper register with a page number, all you need to do is write to the >4000 block. To determine which mapper register you wish to change, use the follow calculation: MRAD = 2 * Register# + >4000 So that to clear mapper register 10, you would use: 2 * >A + >4000 = >4014 CLR @>4014 * Clear Register 10 Note, you can also read from a mapper register, for the purpose of saving previous page values: SPAGE BSS 2 * Hold Page # EXMPL MOV @>4014,@SPAGE * Get MR10 CLR @>4014 * Clear MR10 . . . MOV @SPAGE,@>4014 * Restore Page RT Because writing to the mapper registers is just writing to an address, indirect addressing could be used as well. For example, Consider setting up the mapper so that when in map mode, addresses are the same as in pass mode. It is always a good idea to first set up the mapper registers, and then go into map mode. While in map mode, registers can be changed at will to point elsewhere. If your code to do mapping resides in upper memory, take care NOT to change the register where your code is executing. Pointing to some other place in memory will continue execution on the new page, causing undesired, or unknown results. It is possible though, to point to a new page where code is executing, provided that valid code exists at the current offset and new page. Below is an example which sets up the mapper registers as normal 32k pass mode, yet places the mapper into map mode. The registers can be changed later to access other pages of memory. PAGES DATA >0A00,>0B00,>0C00 DATA >0D00,>0E00,>0F00 START LI R12,>1E00 * AMS CRU LI R1,PAGES * Page Table LI R2,>4014 * Start at MR >A LI R3,6 * 6 Pages to set SBO 0 * Enable MR's RSET MOV *1+,*2+ * Write to MR DEC R3 * Dec counter JNE RSET * Continue SBZ 0 * Disable MR's SBO 1 * Enable map mode END IMPORTANT: Note that the 5 bit page value is placed in the most significant byte of the mapper register. Because only 5 bits are used in a map register, and because the 2 cycle read/write on the data bus loads the most significant byte last, the mapper is loaded with this value. Therefore, page >18 would be >1800, page >05 would be >0500, etc. It might be worthwhile that AEMS addresses page numbers normally, since 12 bits are used instead. ---------------------------------------- PART TWO: Overlay Techniques ============================ Because the AMS system is able to map overlays up to 24k in length, on 4k boundaries, it lends itself well to program development using overlays. First, a root segment is established, which will contain the code to call an overlay. The root segment must remain in memory (without using tricky code to map it out), and will contain the routine used to call an overlay subprogram. We recommend the following: 1) Place the root segment into low memory (8k). 2) Make all overlay calls BLWP routines. Below is the stub code for both the root segment overlay manager, which is used to handle the simulation of a BLWP vector for a mapped environment. **************************************** * Overlay Manager * Version 1.0 * R.A.Green OVMGR SBO 0 * Enable map regs MOV *R11+,R10 * Get N # pages MOV *R11+,R9 * Get 1st map reg MOV *R11+,R7 * Get 1st page # OMGR2 MOV R7,*R9+ * Set mapper reg AI 7,>0100 * Add 1 to page # DEC R10 * Loop for N pages JGT OMGR2 * Finish loop SBZ 0 * Disable map regs MOV *R11,*R11 * Get real BLWP vec MOV *R11+,R7 * Get WSP MOV *11,R9 * Get sub address MOV R13,@26(R7) * Simulate BLWP MOV R14,@28(R7) * MOV R15,@30(R7) * OMGRW EQU $-12 * OVMGR workspace LWPI 0 * R6,R7 user wrkspc B @0 * R8,R9 call sub BSS 2 * R10 BSS 2 * R11 DATA >1E00 * R12 AMS CRU addr BSS 6 * R13 - R15 **************************************** Below is the code which replaces the original BLWP call in the root segment. This is done for every subroutine that generates an overlay. * Overlay Call * Version 1.0 * R.A.Green * BLWP @OSUB OSUB DATA OMGRW * Manager WSP DATA $+2 * BL @OVMGR * Use overlay manager DATA N * # Pages in overlay DATA >40xx * 1st mapper reg addr DATA n * 1st page number DATA sub * REAL BLWP vector **************************************** In order to generate a call for an overlayed subroutine, the real BLWP call must be replaced by the OSUB information. Now, the overlay generator needs to know: 1) How many pages the overlay is. Remember that it can be 4k-24k in length, broken into 4k pages. The routine needs to know what mapper registers to start mapping the 'N' pages in at. The first page number the overlay resides on is also given, along with the ACTUAL BLWP vector address for the overlayed routine. To illustrate this, let us say our root segment is in the >2000 - >3FFF block. We have created an overlay, and inside the overlay is a routine called INPUT, for which the BLWP vector starts at >C2E0. The overlay is in page >18 of memory, and is only 4k, or 1 page in length. To call the overlay, we would use the following code: BLWP @OSUB1 * Call overlay stub DATA >0001 * 1 page long (4k block) DATA >4018 * >C000 block DATA >1800 * 1st page # (only one) DATA >C2E0 * BLWP Vector Note, it would be very useful to have a program loader to load segments of code into different pages. Although such a loader exists for AMS, it is only used for AMS files with special headers for overlay and root segments. A similair loader can be constructed, which loads the overlays into their corresponding pages. The overlay code examples above, are the code segments installed (automatically) by the linker. That eliminates the need for passing the arguments to the overlay generator, and keeping track of relative page addresses. You may however, choose your own method of overlaying. We made it very flexible to customize your software so you can choose how you want to map. Keep in mind that other programs may be resident to AMS, and using the linker/loader will ensure that AMS programs are page relocatable, and won't overwrite memory resident code. ---------------------------------------- PART THREE: Using Hot Bug with AMS ================================== Most often overlay programs are tedious to debug. If you have access to Charles Earl's Hot Bug debugger, I recommend you learn how to use it. It is by far one of the best debugging utilities available, and can certainly work well for debugging AMS programs. Since Hot Bug will also load program files, you can use the debugger to change the page map, and load in your overlay code! Hot Bug Command Summary ER - Edit Register EW - Edit Word DM - Display Memory SPC - Set Program Counter G - Go (# of steps) In order to access the registers, and check the code/data within pages, we need to enable both the mapper, and the registers. Choose a word of memory that does not have code to use the following commands: (For this example, I use >3FF0) 1: ER 12 1E00 2: EW 3FF0 1D00 3: EW 3FF2 1D01 4: SPC 3FF0 5: G 2 (1: Load Register 12 with CRU >1E00) (2: Put SBO 0 at 3FF0 Enable REGS ) (3: Put SBO 1 at 3FF2 MAP Mode ) (4: Set program counter to >3FF0 ) (5: Execute 2 instructions ) NOTE: If the mapper is in an unknown state, (register values unknown), you will want to set the registers before actually placing into map mode. Just use G 1 instead, edit the registers (see below) and then G 1 again to get into map mode. To read/write to the mapper registers, use the DM command to look at the >4000 block. Only addresses >4000 - >4020 are of interest to us. (Mapper regs 0 - 16). NOTE: Even though the upper 24k is mapped using mapper registers 10 - 16, the other mapper registers can be used for temporary storage. 1: DM 4000 (1: Display Memory at >4000) In order to change a register value, just use the EW command. For example, to load mapper register 11, (>B000 block) with page >15, use the following: 1: EW 4016 1500 (1: Load mapper register 11 with >15) Now let's try an experiment. What we will do is write the same page to 2 different mapper registers, and observe what happens. Use the following commands: 1: EW 4014 1500 2: EW 4016 1500 3: DM A000 (1: Load mapper register 10 with >15) (2: Load mapper register 11 with >15) (3: Display memory at >A000 ) Note what the data in memory is at >A000. Now, if you use DM B000, you should see the same data you saw before. Let's try something interesting. Use the following commands: 1: EW A000 FACE 2: DM B000 (1: Put value >FACE into >A000) (2: Display memory at >B000 ) When you use the DM B000, you should get a surprise. When you wrote to A000, you actually changed the word at B000, as well as A000. Why? Because both 4k block point to the same page! Perhaps now you can envision some of the interesting tricks you can accomplish with the AMS system. One such application is the arbitrary locating of data buffers! It is also possible to load a memory image file, on non-consecutive pages, and yet still load the mapper registers such that the program is contiguous in the upper 24k! If that's so, then it means we can load E/A option 5 program files anywhere inside AMS, and then just map in their pages to the proper blocks in high memory! In this manner, even code with absolute origins becomes page relocatable, at least for paging purposes. By placing page numbers into the registers, and using Hot Bug's LOAD command, you can load overlay image files. Keep track of the address for the BLWP vector in the overlay, as well as the page you LOAD it into, and how many pages it takes up. This information you will need to pass to the overlay generator in your program. See? Loading, debugging, and running overlay code on the AMS system is very feasible, and not difficult. ---------------------------------------- This concludes this section of programmer's documentation. The next document will focus on the memory resident utility routines, which AMS programmers can use in their software. Memory allocation, exit code, memory moves, and far VDP read/write routines are available. Also, AMS program have access to the E/A 5, and AMS Overlay program file loader. The loader will load either type of file. The exit routines for AMS have the option of keeping the programmer's code resident for instant execution when desired. We have worked very hard for the past couple of years, to make this memory expansion as user friendly as possible. We are, and will continue to supply support for the AMS card. Without the software support to use AMS, it would just be an expensive paperweight. <<< Joe Delekto >>> Bingo. Thanks. 1 Quote Link to comment Share on other sites More sharing options...
marc.hull Posted June 14, 2018 Author Share Posted June 14, 2018 (edited) So if someone could verify this. The SAMS card has 8 registers mapped starting @ $4000 and looks like this. Reg : 9900 memory map -------- : ------------------- 4000 : 2000-2fff 4002 : 3000-3fff 4004 : a000-afff 4006 : b000-bfff 4008 : c000-cfff 400a : d000-dfff 400c : e000-efff 400e : f000-ffff And for the kicker... All you have to do is write any value from 0-255 to a register and that pages in that particular 4k segment of SAMS RAM into the 9900 map ? Edited June 15, 2018 by marc.hull Quote Link to comment Share on other sites More sharing options...
+adamantyr Posted June 15, 2018 Share Posted June 15, 2018 Mostly correct! Except that in SAMS you actually map the entire address, not just the RAM sections. So it's like this: 4000: 0000-0FFF 4002: 1000-1FFF 4004: 2000-2FFF 4006: 3000-3FFF 4008: 4000-4FFF 400A: 5000-5FFF 400C: 6000-6FFF 400E: 7000-7FFF 4010: 8000-8FFF 4012: 9000-9FFF 4014: A000-AFFF 4016: B000-BFFF 4018: C000-CFFF 401A: D000-DFFF 401C: E000-EFFF 401F: F000-FFFF Obviously mapping to ROM areas has no effect in this instance. 1 Quote Link to comment Share on other sites More sharing options...
RXB Posted June 15, 2018 Share Posted June 15, 2018 Mostly correct! Except that in SAMS you actually map the entire address, not just the RAM sections. So it's like this: 4000: 0000-0FFF 4002: 1000-1FFF 4004: 2000-2FFF 4006: 3000-3FFF 4008: 4000-4FFF 400A: 5000-5FFF 400C: 6000-6FFF 400E: 7000-7FFF 4010: 8000-8FFF 4012: 9000-9FFF 4014: A000-AFFF 4016: B000-BFFF 4018: C000-CFFF 401A: D000-DFFF 401C: E000-EFFF 401F: F000-FFFF Obviously mapping to ROM areas has no effect in this instance. After Asgard started selling the AMS I asked then why not in the future we could not bateryback the card and make use of : 4000: 0000-0FFF 4002: 1000-1FFF 400C: 6000-6FFF 400E: 7000-7FFF As this would really improve the TI types of software and would allow for a true DOS OS. Quote Link to comment Share on other sites More sharing options...
RickyDean Posted June 15, 2018 Share Posted June 15, 2018 Rich, There are already battery backed Sram options available, like a DALLAS DS1230Y-120 DIP-28 256k Nonvolatile SRAM, that might be plug and play type options. I have to do some experimenting on my SAMS some time. DALLAS DS1230Y-120 DIP-28 256k Nonvolatile SRAM 1 Quote Link to comment Share on other sites More sharing options...
Asmusr Posted June 15, 2018 Share Posted June 15, 2018 Yes it would be nice to be able to page in RAM at >0000 - 1FFF and >6000 - >7FFF, but I don't think that's technically possible, or what? 1 Quote Link to comment Share on other sites More sharing options...
+mizapf Posted June 15, 2018 Share Posted June 15, 2018 Not without cutting traces on the main board. The selector circuits turn on the ROMs, and they surely cannot be overridden in the same way as the GROMs. Quote Link to comment Share on other sites More sharing options...
RXB Posted June 15, 2018 Share Posted June 15, 2018 To bad the ROMS are not socketed so could be updated or changed. Quote Link to comment Share on other sites More sharing options...
marc.hull Posted June 15, 2018 Author Share Posted June 15, 2018 Mostly correct! Except that in SAMS you actually map the entire address, not just the RAM sections. So it's like this: 4000: 0000-0FFF 4002: 1000-1FFF 4004: 2000-2FFF 4006: 3000-3FFF 4008: 4000-4FFF 400A: 5000-5FFF 400C: 6000-6FFF 400E: 7000-7FFF 4010: 8000-8FFF 4012: 9000-9FFF 4014: A000-AFFF 4016: B000-BFFF 4018: C000-CFFF 401A: D000-DFFF 401C: E000-EFFF 401F: F000-FFFF Obviously mapping to ROM areas has no effect in this instance. That's very good info and thank you. Makes the card a bit dangerous if you can duplicate memory locations with different contents. I wonder why the design included the option of paging over the ROM and $8000 areas. Anyway this post will give me the confidence to at least think I'm on the right track. 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.