Kylev Posted June 15, 2012 Share Posted June 15, 2012 Hi All, As an exercise for myself, I am attempting to write a checkbook balancing program that utilizes the extended memory in a 130xe. I am trying to use the four extended banks for data storage of transaction records, leaving the main bank for program use. I am using an assembler subroutine to perform the bank switching and data storage/retrieval with the last function being a return to standard memory map before returning to the calling Basic program. My thinking was that Basic could not handle losing any program lines that fall in the bank window, so I pass control to the machine language subroutine and then restore the main bank before Basic needs to do any further processing. Everything works well so long as my Basic program does not encroach on the bank window, but once the program takes up residence past $4000 I am having a problem with the computer becoming locked up. This lock up does not happen during program execution. It happens if I exit the program (either by Break or quiting the program normally) and then try to set PORTB to any value. I am still in the early stages of program development and want to verify that the data I think is being stored in a given bank is really getting there in the layout I have set up. Am I truly hitting a system limitation here, or is it more likely that the logic of my subroutine is somehow flawed and I am confusing the OS to the point that it just gets lost? I can post both the Turbo Basic code and the source for the machine language subroutine if that will help. Thanks, Russ Quote Link to comment Share on other sites More sharing options...
Rybags Posted June 15, 2012 Share Posted June 15, 2012 Immediate Basic mode is like running from line 32768. So the problem is anything you type will be tokenized at the end of the program, and any variables will be after that. If the program ended at $8010 then you'd probably have fewer problems. But another thing is line searching, Atari Basic always searches from the start of program, and the links will be broken if the wrong bank is in place and it needs to skip through part of the program that falls in the switchable area. If you could get away with using strings and integers to access the extended banks then it'd be easy to transfer data via a USR routine. I don't think Turbo Basic has ability to return address of a numeric array otherwise you might be able to move stuff in/out of those too. Another alternative could be to use ext Ram as a Ramdisk and use I/O statements to transfer data. Or if you want to stick to the way you're doing things, another alternative - fill your program with REM statements to bloat the program out so it ends after $8000. As you expand the program, remove these lines to fit. At least then you should find immediate mode works to an extent. 1 Quote Link to comment Share on other sites More sharing options...
+JAC! Posted June 15, 2012 Share Posted June 15, 2012 (edited) Turbo Basic itself makes heavy use of PORTB because it utilizes the memory below the OS an assumes it has total over it. In particular Turbo Basic has the NMI/IRQ handlers in the lower RAM area and the sitches PORTB as required. It mostly uses INC PORTB and DEC PORTB to switch BIT0. I assume what happens in you case is that NMI/IRQs kick in while your assembler routine is running. If they kick in while PORTB is in a state Turbo Basic does not expect, the stack/state will break. In normal Atari BASIC this problem does not exists, because it doesn't change PORTB. So you should make sure your code looks like: sei ;Prevent IRQ lda #0 sta $d40e ; Prevent NMI lda $d301 pha ... pla ;Restore PORTB sta $d301 lda #$40 ;Re-enable VBI sta $d40e cli ;Re-enable IRQ rts Edited June 15, 2012 by JAC! 1 Quote Link to comment Share on other sites More sharing options...
+MrFish Posted June 15, 2012 Share Posted June 15, 2012 Here's a ML subroutine that gives you access to the extended RAM in a 130XE. It was written for regular Atari BASIC and works with Turbo BASIC as well. It was taken from Compute magazine. Thanks goes to AA user ThumpNugget for the original scans. 30200 PROC InitAccessBanked 30240 FOR PageSixMem = 1536 TO 1780 30260 READ MachineCodeByte 30270 POKE PageSixMem, MachineCodeByte 30280 Next PageSixMem 30300 DATA 160,0,173,1,211,41,195,133,217,165,216,41,192,74,74,74,74,9,32,5,217,141,1,211,165,216,41,63,9,64,133,215 30310 DATA 165,212,145,214,165,217,9,48,141,1,211,96,160,0,173,1,211,41,195,133,217,165,216,41,192,74,74,74,74,9,32 30320 DATA 5,217,141,1,211,165,216,41,63,9,64,133,215,177,214,133,212,165,217,9,48,141,1,211,96,104,133,245,198,245 30330 DATA 104,133,216,104,133,214,165,245,208,6,32,44,6,132,213,96,104,104,133,212,32,0,6,24,144,243,104,104,133,225 30340 DATA 104,133,224,104,133,216,104,133,214,104,133,227,104,133,226,160,0,132,229,132,228,177,224,133,212,32,0,6 30350 DATA 230,224,208,2,230,225,230,214,208,2,230,216,230,228,208,2,230,229,165,228,197,226,208,225,165,229,197,227 30360 DATA 208,219,96,104,104,133,216,104,133,214,104,133,225,104,133,224,104,133,227,104,133,226,160,0,132,229,132 30370 DATA 228,32,44,6,165,212,145,224,230,224,208,2,230,225,230,214,208,2,230,216,230,228,208,2,230,229,165,228,197 30380 DATA 226,208,225,165,229,197,227,208,219,96 30390 ENDPROC 4 Quote Link to comment Share on other sites More sharing options...
flashjazzcat Posted June 15, 2012 Share Posted June 15, 2012 That's neat. I'm surprised no-one ever tried to do the same thing using a CIO handler... perhaps there'd be a bit of a performance overhead, though. 1 Quote Link to comment Share on other sites More sharing options...
+JAC! Posted June 15, 2012 Share Posted June 15, 2012 Yes, exactly what I mentioned in missing. It assumes interrupts don't mess with PORTB. Do you need it as DATA statements? If you use TurboBasic anyway I could provide an executable which can be loaded via BLOAD. 0600: A0 00 LDY #$00 0602: AD 01 D3 LDA PORTB 0605: 29 C3 AND #$C3 0607: 85 D9 STA $D9 0609: A5 D8 LDA $D8 060B: 29 C0 AND #$C0 060D: 4A LSR 060E: 4A LSR 060F: 4A LSR 0610: 4A LSR 0611: 09 20 ORA #$20 0613: 05 D9 ORA $D9 0615: 8D 01 D3 STA PORTB 0618: A5 D8 LDA $D8 061A: 29 3F AND #$3F 061C: 09 40 ORA #$40 061E: 85 D7 STA $D7 0620: A5 D4 LDA FR0 0622: 91 D6 STA ($D6),Y 0624: A5 D9 LDA $D9 0626: 09 30 ORA #$30 0628: 8D 01 D3 STA PORTB 062B: 60 RTS 062C: A0 00 LDY #$00 062E: AD 01 D3 LDA PORTB 0631: 29 C3 AND #$C3 0633: 85 D9 STA $D9 0635: A5 D8 LDA $D8 0637: 29 C0 AND #$C0 0639: 4A LSR 063A: 4A LSR 063B: 4A LSR 063C: 4A LSR 063D: 09 20 ORA #$20 063F: 05 D9 ORA $D9 0641: 8D 01 D3 STA PORTB 0644: A5 D8 LDA $D8 0646: 29 3F AND #$3F 0648: 09 40 ORA #$40 064A: 85 D7 STA $D7 064C: B1 D6 LDA ($D6),Y 064E: 85 D4 STA FR0 0650: A5 D9 LDA $D9 0652: 09 30 ORA #$30 0654: 8D 01 D3 STA PORTB 0657: 60 RTS 0658: 68 PLA 0659: 85 F5 STA $F5 065B: C6 F5 DEC $F5 065D: 68 PLA 065E: 85 D8 STA $D8 0660: 68 PLA 0661: 85 D6 STA $D6 0663: A5 F5 LDA $F5 0665: D0 06 BNE $066D 0667: 20 2C 06 JSR $062C 066A: 84 D5 STY $D5 066C: 60 RTS 066D: 68 PLA 066E: 68 PLA 066F: 85 D4 STA FR0 0671: 20 00 06 JSR $0600 0674: 18 CLC 0675: 90 F3 BCC $066A 0677: 68 PLA 0678: 68 PLA 0679: 85 E1 STA $E1 067B: 68 PLA 067C: 85 E0 STA FR1 067E: 68 PLA 067F: 85 D8 STA $D8 0681: 68 PLA 0682: 85 D6 STA $D6 0684: 68 PLA 0685: 85 E3 STA $E3 0687: 68 PLA 0688: 85 E2 STA $E2 068A: A0 00 LDY #$00 068C: 84 E5 STY $E5 068E: 84 E4 STY $E4 0690: B1 E0 LDA (FR1),Y 0692: 85 D4 STA FR0 0694: 20 00 06 JSR $0600 0697: E6 E0 INC FR1 0699: D0 02 BNE $069D 069B: E6 E1 INC $E1 069D: E6 D6 INC $D6 069F: D0 02 BNE $06A3 06A1: E6 D8 INC $D8 06A3: E6 E4 INC $E4 06A5: D0 02 BNE $06A9 06A7: E6 E5 INC $E5 06A9: A5 E4 LDA $E4 06AB: C5 E2 CMP $E2 06AD: D0 E1 BNE $0690 06AF: A5 E5 LDA $E5 06B1: C5 E3 CMP $E3 06B3: D0 DB BNE $0690 06B5: 60 RTS 06B6: 68 PLA 06B7: 68 PLA 06B8: 85 D8 STA $D8 06BA: 68 PLA 06BB: 85 D6 STA $D6 06BD: 68 PLA 06BE: 85 E1 STA $E1 06C0: 68 PLA 06C1: 85 E0 STA FR1 06C3: 68 PLA 06C4: 85 E3 STA $E3 06C6: 68 PLA 06C7: 85 E2 STA $E2 06C9: A0 00 LDY #$00 06CB: 84 E5 STY $E5 06CD: 84 E4 STY $E4 06CF: 20 2C 06 JSR $062C 06D2: A5 D4 LDA FR0 06D4: 91 E0 STA (FR1),Y 06D6: E6 E0 INC FR1 06D8: D0 02 BNE $06DC 06DA: E6 E1 INC $E1 06DC: E6 D6 INC $D6 06DE: D0 02 BNE $06E2 06E0: E6 D8 INC $D8 06E2: E6 E4 INC $E4 06E4: D0 02 BNE $06E8 06E6: E6 E5 INC $E5 06E8: A5 E4 LDA $E4 06EA: C5 E2 CMP $E2 06EC: D0 E1 BNE $06CF 06EE: A5 E5 LDA $E5 06F0: C5 E3 CMP $E3 06F2: D0 DB BNE $06CF 06F4: 60 RTS Quote Link to comment Share on other sites More sharing options...
Kylev Posted June 16, 2012 Author Share Posted June 16, 2012 Rybags, If I am understanding your reply, it would seem that Atari Basic is in fact easily confused when the banks get switched. Is that still true when the banks are manipulated during a USR call? I am not trying to do any PORTB changes in the BASIC part of the program. In fact, the last thing the USR routine does is set PORTB back to its default value of 254. I am also using Turbo Basic which is why the PORTB setting includes the value for BASIC off. JAC!, Thanks for telling me about Turbo Basic's internal handling of PORTB. I will try encapsulating my ML routine in the code you described and see where that gets me. I must admit that I am getting lost in the second bit of code you listed. Does it have something to do with MrFish's post? If so, I have not yet digested that piece. Hopefully, your code will make more sense to a novice like myself once I have. MrFish, I have not yet had a chance to fully go over your suggestion, as I mentioned to JAC!. I will certainly go over your input and put it to good use. Thanks. All, Thanks for all the input. I really appreciate your willingness to help as this bump in the road has really got me stumped. I should be trying some of your suggestions out this weekend and I should be posting the results in this thread by Sunday evening (USA West Coast Time, that is). Russ Quote Link to comment Share on other sites More sharing options...
Rybags Posted June 16, 2012 Share Posted June 16, 2012 254 = OS off, Basic Rom on. Unsure if that's what you want. Best practice is to not assume anything, get PORTB state and store it somewhere or push to the stack. A USR routine should be free to do what it wants, but if T-Basic does have IRQ/NMI routines in place then you've got that potential point of failure there. Assuming you don't need the OS or Basic state to be one way or the other, you could use AND/OR to control your bank selecting rather than using specific values. Chances are you could leave IRQs and NMIs enabled as well. Quote Link to comment Share on other sites More sharing options...
Kylev Posted June 16, 2012 Author Share Posted June 16, 2012 Rybags, Strange. I don't have access to my 130xe at the moment and I have been using Altirra for program development. When I use Turbo Basic, I get a value 254 from Peek($D301). Atari Basic does give a value of 253 from a similar Peek. Sounds like a flaw in emulation or else Turbo Basic would have to contain a custom OS to take the place of the installed one. Russ Quote Link to comment Share on other sites More sharing options...
Rybags Posted June 16, 2012 Share Posted June 16, 2012 IIRC Turbo Basic uses Ram under both OS and Basic, that's the reason it's incompatible with many modern Dos setups. If you do a USR routine that returns PORTB you get $FF - T-Basic swaps the OS in/out as required depending on what statement is running. Checking the Ram-based NMI handler - the DLI handler leaves PortB alone so any DLI would have to assume an indeterminate state. Most DLIs don't need the OS Rom present anyway. Any user supplied DLI would need to preserve the state of PORTB. The VBlank handler pushes a return address to the stack so it can get control back, switches PortB to $FF via an INC, then branches thru VVBI ($222). Once control is returned it restores PortB via DEC and returns from the NMI. The Ram-based IRQ handler does the same thing. So, the way things are set up, the state of PortB can change dynamically and the Interrupt handlers will cope with it. The things a user program need to do - when changing PortB, preserve and restore it's state, and don't assume the OS/Basic Rom state will be predictable. Quote Link to comment Share on other sites More sharing options...
Kylev Posted June 16, 2012 Author Share Posted June 16, 2012 Rybags, Thanks. That would explain things. Sounds like I definitely need to employ JAC!'s wrapper code. Quote Link to comment Share on other sites More sharing options...
+JAC! Posted June 16, 2012 Share Posted June 16, 2012 (edited) I've put it back into source, optimized the size so it still fits into page 6 and put in the NMI/IRQ handling. BLOAD "D:ACCESS.XEX" will load it to page 6. New addresses are: auxbyte=$0667 auxdump=$069E auxload=$06C0 Done blindly - I don't have a program to test. So in case it does not work, please post the surounding code also. Access.xex Edited June 16, 2012 by JAC! Quote Link to comment Share on other sites More sharing options...
Kylev Posted June 17, 2012 Author Share Posted June 17, 2012 JAC!, I must have a fundamental misunderstanding of how to apply the wrapper code from your first post. I have attached my subroutine, in text format, to this post. Maybe you can tell where my fatal flaw is located. Here is what is happening. When I run my Turbo Basic program (I am BLOADing my subroutine in as a part of the initialization process), I can execute the proc to enter data for a check record. Upon completion of data entry, the proc moves the record to a reserved buffer in hi memory and calls my subroutine. I get machine lockup at this point. Let me know if you need to see the Turbo Basic code. I can upload it here, if needed. TSTTBRS.TXT Quote Link to comment Share on other sites More sharing options...
+JAC! Posted June 17, 2012 Share Posted June 17, 2012 Hmm, looks like X is intend to hold the bank index, but then it makes no sense to use it only when it's 3 (or 2 for the other case). 0100 PLA ;DISCARD HI BYTE OF FLAG. IT WILL NEVER BE >255 0110 PLA ;GET VALUE FOR FLAG 0120 TAX ;SAVE FLAG IN X REGISTER 0130 PLA 0140 STA INDEX+1 ;HI BYTE OF INDEX TO NEXT RECORD 0150 PLA 0160 STA INDEX ;LO BYTE OF INDEX TO NEXT RECORD 0161 LDA $D301 0162 PHA 0170 CPX #3 ;IS FLAG AN ATM/POS RECORD? 0180 BEQ GOATM ;YES, THEN GO ATM SUBROUTINE ... 0230 GOATM JSR SVPRTB ;RUN ATM/POS SUBROUTINE 0231 JSR ATMSUB .. 0270 ATMSUB LDA BANKCD,X ;GET BANK # FOR ATM 0280 STA $D301 ;SET BANK FOR ATM RECORDS Quote Link to comment Share on other sites More sharing options...
Kylev Posted June 18, 2012 Author Share Posted June 18, 2012 JAC!, X gets used in 3 cases, when it is 0 & 1 then the record is for a check. Banks 0 & 1 are used to store check records. When X is 2, the record is a deposit and Bank 2 is used. When X is 3, the record is for an ATM/POS record and Bank 3 is used. I have only tested the check record piece so far and only the first bank of checks. The value placed into X comes from the Basic program as a part of the USR call. Do I have a logic error in the way I have tried to implement your suggested code? Quote Link to comment Share on other sites More sharing options...
Kylev Posted June 18, 2012 Author Share Posted June 18, 2012 JAC!, I believe I have found at least one logic error. I have an extraneous save for PORTB. I think I am corrupting the stack and this may be what is causing my system lockup. Quote Link to comment Share on other sites More sharing options...
+JAC! Posted June 18, 2012 Share Posted June 18, 2012 Yes, this PLA will pull a byte from the return address which was pushed by JSR. RESET PLA ;GET SAVED PORTB STATE 0570 STA $D301 ;RESTORE PORTB STATE 0580 LDA #$40 ;RESTORE NMI 0590 STA $D40E 0600 CLI ;ENABLE IRQ 0610 RTS Quote Link to comment Share on other sites More sharing options...
Rybags Posted June 18, 2012 Share Posted June 18, 2012 Maybe it'd be easier to write a generic routine to get/put short segments up to 256 bytes. USR allows an integer up to 65535, so you could use that to determine bank and address. Shift high byte left 4 times, AND #$0C gives you the bank number. And high byte with #$3F then OR #$40 gives the absolute address. Quote Link to comment Share on other sites More sharing options...
Kylev Posted June 19, 2012 Author Share Posted June 19, 2012 JAC!, I failed to save the state of $D301 in the source code I uploaded earlier. Here is a corrected version. This code seems to execute, but returns to a Basic READY prompt with a lock-up. Progress, but not exactly the intended result. I think I am doing the following: Basic places the length of the record, a bank flag, and the offset into the bank on the stack. The subroutine pulls each of these elements from the stack, leaving just the return address for the USR call. The routine calls the code to stop maskable interrupts, Non-maskable interrupts, and then places the current state of $D301 onto the stack. The requested record type is stored in extended memory The routine calls the code to restore the state of $D301, returns execution of Non-maskable interrupts to service, returns maskable interrupts to service and then returns to Basic Some part of this is not true. I am just not getting the part that is broken. Can you make any suggestions for what to look at? Rybags, Sir, your assembler accumen is beyond my measley understanding. I am having trouble grasping how the high byte of an integer (multiplied by 16 and having its bit2 & bit3 masked off) can give the selected bank. Don't get me wrong. I believe you when you say this works. I just can't make that leap in my own head. Can you explain the workings? Thanks. TSTTBRS.TXT Quote Link to comment Share on other sites More sharing options...
Kylev Posted June 19, 2012 Author Share Posted June 19, 2012 All, I have confirmed that any time my program invades addresses above $4000, I cannot issue a POKE command to $D301 without a lockup being the result. I have determined a somewhat clumsy work around for testing purposes. Load and run the program implementing an ML subroutine containing the wrapper code JAC! recommended. When the test run is complete, quit the program. Type NEW to remove any program lines that might be living in the access window. Issue the immediate mode command to set PORTB to the required value. Validate that the expected data is there. Cold start, reload the program and continue testing. A bit more cumbersome than I would like, but it works. I want to thank both MrFish and JAC! for supplying a canned solution that I may still choose to implement, but I think I will continue to test with my own code for now. It is helping me to become familiar with 6502 assembler in ways that a pre-programmed solution would not. Quote Link to comment Share on other sites More sharing options...
+MrFish Posted June 19, 2012 Share Posted June 19, 2012 I've put it back into source, optimized the size so it still fits into page 6 and put in the NMI/IRQ handling. BLOAD "D:ACCESS.XEX" will load it to page 6. New addresses are: auxbyte=$0667 auxdump=$069E auxload=$06C0 Done blindly - I don't have a program to test. So in case it does not work, please post the surounding code also. This is interesting information. I've been using the routine that I posted above with Turbo-BASIC since the late 80's. I've never experienced a problem with the routine or Turbo-BASIC itself as a result. As a matter of fact I'm currently using this routine in my font converter for the GUI, with which I've converted hundreds of megabytes of font data. Is it possible to give a more concrete example of how the problem would manifest itself as a result of using the routine that I've posted? Quote Link to comment Share on other sites More sharing options...
Kylev Posted June 20, 2012 Author Share Posted June 20, 2012 MrFish, Was this last post directed at me or JAC!? I have not implemented ACCESS in my program, yet. I have been testing with my home-grown routine wrapped in JAC!'s code to toggle IRQ & NMI at appropriate places. I need to compare how ACCESS uses PORTB with my routine. I might find something enlightening. Hopefully, I will get to this before week's end. I will keep you posted. Quote Link to comment Share on other sites More sharing options...
+MrFish Posted June 20, 2012 Share Posted June 20, 2012 MrFish, Was this last post directed at me or JAC!? I have not implemented ACCESS in my program, yet. I have been testing with my home-grown routine wrapped in JAC!'s code to toggle IRQ & NMI at appropriate places. I need to compare how ACCESS uses PORTB with my routine. I might find something enlightening. Hopefully, I will get to this before week's end. I will keep you posted. It was directed more at JAC, or Rybags. I know you're trying to improve your assembler experience Kylev. I just posted the routine for reference, or for anybody who's never seen it before. Quote Link to comment Share on other sites More sharing options...
Kylev Posted June 21, 2012 Author Share Posted June 21, 2012 MrFish, Thanks. I appreciate your help in this learning curve. Quote Link to comment Share on other sites More sharing options...
Synthpopalooza Posted October 3, 2012 Share Posted October 3, 2012 I was looking for information on 130XE bankswitching, and came across this thread ... this routine could serve my needs, but I have a few problems. The situation is, I am experimenting with a Puzzle Bobble type game ... it uses a software graphics mode, so I'm basically using a VBI, a character set DLI, and two stored display lists. My memory map for this is: VBI: 1536 (start of page 6) Display list 1: 1576 Display list 2: 1654 (31 bytes) DLI: In a string Table for VBI: 1024 (start of page 4) Table for DLI: 1058 Character sets: 16 pages below RAMTOP I also want to bring PMG's into this as well, and the idea is to store character sets in extended ram and move them into my char set memory as they are needed. The game will have 15 sets of level graphics, which will all fit into the extended memory of the 130XE. The problem is, the routine (as shown in the compute magazine article) resides in the start of page 6, but I am using that area for my VBI and display lists. Ideally I want the routine to reside starting at 1686 (past the end of my second display list) ... how do I modify this routine to achieve this? I am including the .ATR here with the accompanying program PB1.TUR if anyone here wants to have a look and see what I've done. Lines of note: 600-620: Reserve 16 pages below RAMTOP and load fonts 630-640: POKE in Display List 1 (Antic 2 - Graphics 10) 650-850: POKE in Display List 2 (Antic 4 - Graphics 12 with horizontal scrolling) 900-950: Initialize VBI routine 951-954: Initialize DLI routine (the routine is at line 20000) 960: Display screen puzzle bobble level 1 ice font test.atr 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.