swap out basic ...

Started by stiggity, July 26, 2010, 10:09 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

stiggity

Hello:
In the 64 example code below, when this routine is called, basic is swapped out. And Machine Language can be stored at $A000 - $BFFF, which comes in handy trying to find room for routines. Is there a routine using the 128 where something similar can be done. Keep in mind, i dont know much about the 128, but am willing to learn. A c64 programming friend of mine told me to change banks... is it that e-z.. or after changing to a different bank, would "new" ML need to be loaded in??





SWAP  STA      SWAP2 ;store accum for later use
          LDA      $01     ;8bit I/O register
          AND      #$FE
          STA      $01
          LDA      SWAP2  ;recover accum and return
          RTS

SWAP1 STA     SWAP2
           LDA     $01
           ORA     #$01     ;swap basic back in
           STA      $01
LDA     SWAP2
           RTS

BigDumbDinosaur

Quote from: stiggity on July 26, 2010, 10:09 AM
Hello:
In the 64 example code below, when this routine is called, basic is swapped out. And Machine Language can be stored at $A000 - $BFFF, which comes in handy trying to find room for routines. Is there a routine using the 128 where something similar can be done. Keep in mind, i dont know much about the 128, but am willing to learn. A c64 programming friend of mine told me to change banks... is it that e-z.. or after changing to a different bank, would "new" ML need to be loaded in??

SWAP  STA      SWAP2 ;store accum for later use
          LDA      $01     ;8bit I/O register
          AND      #$FE
          STA      $01
          LDA      SWAP2  ;recover accum and return
          RTS

SWAP1 STA     SWAP2
           LDA     $01
           ORA     #$01     ;swap basic back in
           STA      $01
LDA     SWAP2
           RTS
There you go again with the hard-coded stuff.  Geesh!  Have a look at the following and try rewriting your routine as a professional would do it:

;MOS TECHNOLOGY 6510 BASIC HARDWARE DEFINITIONS
;
d6510    =$00                  ;on-chip data direction
r6510    =$01                  ;on-chip data port...
;
;    00xxxxxx
;      ||||||
;      |||||+---> (/LORAM)  0 = RAM at $A000-$BFFF
;      ||||+----> (/HIRAM)  0 = RAM at $A000-$BFFF & $E000-$FFFF
;      |||+-----> (/CHAREN) 0 = character ROM at $D000-$DFFF
;      |||                  1 = I/O at $D000-$DFFF
;      ||+------> cassette data out
;      |+-------> 0 = cassette switch opened
;      +--------> 0 = cassette motor on
;
hwstack  =$0100                ;hardware stack
v_irqbrk =$fffe                ;IRQ/BRK vector
v_nmi    =$fffa                ;NMI vector
v_reset  =$fffc                ;hard reset vector



BTW, why not just PHA...PLA instead of using RAM to protect .A?

As for mapping out BASIC on the 128, if you were to read about the MMU in Mapping the Commodore 128, you'd learn how to set up any memory map you want.  There is a booby-trap though, which you would also learn about by reading Mapping the Commodore 128.   ;D   I'll give you a little hint:  BASIC text can extend up to $FF00 in RAM-0, so mapping out the BASIC ROMs wouldn't necessarily give you access to unused memory.
x86?  We ain't got no x86.  We don't need no stinking x86!

stiggity

BDD:
I even tried to label my routines, so you could read them.. now i know this is going to make me sound stupid (not that i am not already), your reply is just a bunch of labels.. there is no physical code. I was sort of looking for a 128 oriented alternative to my 64 oriented routine..

-Steve

stiggity

Sorry for the multiple posts.. im 100% new at this..
BDD
I am sort of looking for help, as i have never been able to read from books. But i can learn from examples... If i want to store a bunch of ML subroutines and still have basic and the kernal, how would i decide on which bank to use, or how do i store ML im bank 0, then switch back to basic. learning banking is the reason i never worked on the 128 in the first place, but now i sorta have to learn. Any examples, etc. My program for the 64 uses $A000 - $CFFF and thats just enough room to store the programs ML routines, and i use the above "SWAP" to toggle in and out of the routines under basic. Ive never had a problem doing that, and it has worked so far... how would i swap out 128 basic in bank15 and if i did manage to swap out basic what address would be fair game to store some ml routines.. thank you very very much..

-Steve

BigDumbDinosaur

First off, when working purely in the M/L environment, don't think in terms of banks.  They are mostly of value to the BASIC programmer who wants to call an M/L sub from basic (e.g., BANK 15:SYS ML,A,X,Y,P).  Once in your M/L program, use configuration masks written to the MMU to establish your memory map.

Unlike the C-64, which had 4k of exposed and uncommitted RAM at $C000, as well as 8k of unused RAM under the BASIC ROM, another 8K under the kernel ROM and 4k under the I/O block, the 128 has little such memory.  The largest uncommitted stretch of RAM in the 128 extends from $01300 to $01BFF, which is in RAM-0.  Unless a VIC graphic screen has been set up by using a GRAPHIC statement in BASIC, BASIC program text will start $01C01 and is allowed to extend up to $0FEFF, using up all the space under the ROMs and I/O block.  BASIC variable storage will extend from $10400 to $1FEFF in RAM-1.  Aside from the cassette buffer ($00B00) and the RS-232 buffers ($00C00-$00DFF), there's really not much left.  You could use the sprite definition area at $00E00 and thus load a routine of up to 1.1k in size, assuming the load address is $00B00.

Several methods exist to get more space for an M/L routine while still using BASIC.  One of them is to issue a GRAPHIC 1 statement in BASIC, which will shift the start of BASIC up to $4000 (the text is moved as well), thus allowing you to load an M/L program into RAM starting at $01300 and extending to $03FFF. a bit over 11k of RAM.  The value of this is the ROMs and I/O block will be available for use by your M/L code.  The obvious limitation is you cannot use the 40 column screen and if you accidentally use one of the graphics functions that draws shapes, your M/L will get stepped on.

Another possibility is to load your routine in high RAM, and protect it from BASIC by lowering the top-of-BASIC pointers.  The obvious disadvantage to this method is you can't conveniently use any ROM routines, as mapping in the ROMs would obscure your program.  JSRFAR won't help in this regard, as it doesn't restore the configuration that existed prior to the call.  You'd have to create your own version JSRFAR.

It is also possible to run M/L in RAM-1, either by raising the bottom of RAM-1 storage (which starts at $10400) or by lowering the top of storage.  Raising the bottom  of storage is better, in that you can easily maintain a configuration that keeps ROM exposed.  If you code runs in the bottom of RAM-1 you can call any ROM routine you want as long as that routine will return you to your RAM-1 configuration.

If you need the ability to do rapid cross-bank transfers, you could also define a 1k common area at the top of RAM for the code, after you lower the top of BASIC and top of variable storage.  The 128 has a lot flexibility...you just have to know how to use it.

All of this is covered in detail in Mapping the Commodore 128.
x86?  We ain't got no x86.  We don't need no stinking x86!

BigDumbDinosaur

Quote from: stiggity on July 26, 2010, 11:44 PMI even tried to label my routines, so you could read them.. now i know this is going to make me sound stupid (not that i am not already), your reply is just a bunch of labels.
That was the point: use labels, not hard-coded references.  Using the label method, your C-64 RAM exposure routine could be written thusly:

;MOS TECHNOLOGY 6510 BASIC HARDWARE DEFINITIONS
;
d6510    =$00                  ;on-chip data direction
r6510    =$01                  ;on-chip data port...
;
;    00xxxxxx
;      ||||||
;      |||||+---> (/LORAM)  0 = RAM at $A000-$BFFF
;      ||||+----> (/HIRAM)  0 = RAM at $A000-$BFFF & $E000-$FFFF
;      |||+-----> (/CHAREN) 0 = character ROM at $D000-$DFFF
;      |||                  1 = I/O at $D000-$DFFF
;      ||+------> cassette data out
;      |+-------> 0 = cassette switch opened
;      +--------> 0 = cassette motor on
;
;
;===============================================================
;
;EXPOSE RAM UNDER BASIC
;
expose   pha                   ;protect
         lda r6510             ;MPU data port
         and #%11111110        ;map out BASIC
;
expose01 sta r6510             ;configure memory map
         pla                   ;restore
         rts
;
;===============================================================
;
;HIDE RAM UNDER BASIC
;
obscure  pha                   ;protect
         lda r6510             ;MPU data port
         ora #%00000001        ;map in BASIC
         bne expose01
;


Almost anyone with some M/L experience would have no trouble understanding what the above code does.

Quote...there is no physical code. I was sort of looking for a 128 oriented alternative to my 64 oriented routine.
There is no simple alternative.  The C-64's memory mapping scheme is simplistic when compared to that of the 128's.  The 64 doesn't load BASIC code under the ROMs, nor does it continuously change the memory map as BASIC is executing.  With the 128, you write configuration masks into the MMU, which produce a widely varying combination of RAM, ROM and I/O.  It's up to you to figure out what you want and the corresponding mask to use on the MMU.
x86?  We ain't got no x86.  We don't need no stinking x86!

stiggity

BDD:
Excellent read!!! thats the kind of text I enjoy reading. And Yes, I fully understood your Labeled example, to the "T"!! Another thing, I 100%, really enjoy and appreciate u helping a "Newb" understand the differences between a c128 and a c64. You may not believe this, but , by myself, i wrote an entire BBS prg for the c64. _And_, its available via telnet over the WWW. I'll include a link below.

    Since my prog has been accepting calls for a good 9months, I decided to embark on a journey, to try with the little ML experience i had, to write a BBS program for the 128 using the VDC. Yourself, and Lokalhorst have steered me clear of the obsticles keeping me from giving up almost right from the get go.
Much thanks to the individuals here at 128 & pet alive.

-Steve

MIRKOSOFT

Hi!


Also, you can call routines which are in disabled ROM.
It's simple - subroutine must be in always visible part of RAM and in it then change bank to enable ROM where routine is, then save value which you need or st. other, then give bank back and RTS, all done.


Miro
MIRKOSOFT of megabytes

Commodore 64 was great, Commodore 128 is bigger, better, faster and more!!!

http://www.mirkosoft.sk

stiggity

BDD:
Im currently using the "graphic 1" command, to store ML from $1300 to $3FFF. Im running into a problem now. In your explanation, u said if u use any graphics commands your ml will get stepped on. Does this include a "window" draw. Im drawing a "window 0,6,79,24" when i activate my clock and lightbar IRQ $314/$315, they both work,. but as soon as i draw the window.. it usually acts-up.. b ut always ends-up not working.. i know the window commnad is not a "graphic" command.. but thats why im asking you!

-Steve

BigDumbDinosaur

Quote from: stiggity on July 28, 2010, 12:53 PMIm running into a problem now.  In your explanation, u said if u use any graphics commands your ml will get stepped on. Does this include a "window" draw. Im drawing a "window 0,6,79,24" when i activate my clock and lightbar IRQ $314/$315, they both work,. but as soon as i draw the window.. it usually acts-up.. b ut always ends-up not working.. i know the window commnad is not a "graphic" command.. but thats why im asking you!
What WINDOW does is change the printable screen margins by changing a set of zero page locations used by the screen kernel, followed by repositioning the cursor into that area of the screen.  Since the VDC's cursor is a hardware feature, the use of WINDOW automatically results in a VDC access, all of which you'd know if you read Mapping the Commodore 128.

Your problem is you are trying to make the VDC serve two masters: the screen kernel and your IRQ.  You can't have both.  If foreground display activity is in progress when an interrupt occurs, you cannot access the VDC, as doing so will cause register changes that the screen kernel will not know about.  You'd have to sniff the stack following an IRQ to see if the screen kernel was interrupted and if so, defer VDC access.
x86?  We ain't got no x86.  We don't need no stinking x86!

stiggity

BDD:
>> You'd have to sniff the stack following an IRQ to see if the screen kernel was interrupted and if so, defer VDC access.

I know u have been following some of my posts, and replying, and honestly you have been a great help in this project. And, as u probably know im not the best at writing assembly, or bit-fiddling. How would i go about sniffing the stack folllowing and IRQ, to see if the screen kernel was interrrupted, and if so, defer VDC access?

    I know your not a big fan of writing peoples programs for them, but if you could include some hints, or memory locations it would be a big help. As this is the kind of ML routine i have never encountered..

    Is it possible to run a clock IRQ, _and_ use the window command?

Regards,
-Steve

BigDumbDinosaur

Quote from: stiggity on July 30, 2010, 01:52 AMHow would i go about sniffing the stack folllowing and IRQ, to see if the screen kernel was interrrupted, and if so, defer VDC access?
This is stuff that is essential to know if you are going to write IRQ code that won't upset the applecart.  Sniffing the stack means determining the address that was in the MPU's program counter at the time of the interrupt.

If you recall, when the 65xx family responds to an interrupt, the status register and program counter are pushed onto the stack before the MPU takes the relevant vector.  The PC is pushed MSB/LSB after SR.  In the C-128, the IRQ front end also pushes the three MPU registers and the mask in the MMU configuration register at $FF00 onto the stack, resulting in a total of seven stack entries.

Next, a determination is made as to whether the interrupt was hardware (IRQ) or software (BRK).  In your case, it would be hardware, causing the MPU to jump through $00314, which normally points to the continuation of the IRQ handler in ROM.  In your case, you would have modified the address at $00314-$00315 to point to your handler.

When your IRQ handler is executed, the stack pointer will be pointing below the MMU value that was pushed during the initial processing of the interruptâ€"effectively it's as though the system performed SP=SP-7.  So, if you transfer the stack pointer into the .X register (TSX) and get the sixth and seventh values off the stack, you have the address of the instruction that will be executed when the MPU returns from the interrupt (RTI).  You can then use that information to see if the address range in the screen kernel that affects the VDC was interrupted:

;    screen kernel conflict detection definitions...
;
hwstack  =$0100                ;MPU hardware stack
scrnkerl =$c53c                ;screen kernal low end
scrnkerh =$ce4c                ;screen kernal high end               
stakdpth =7                    ;stack sniff depth
;
;
;    determine if screen kernel was interrupted...
;
ccih01   tsx                   ;get stack pointer
         lda hwstack+stakdpth,x
         ldy hwstack+stakdpth-1,x
         cmp #>scrnkerl        ;low end of screen kernel MSB
         bcc ccih03            ;not interrupted
;
         bne ccih02            ;not at low end, check high
;
         cpy #<scrnkerl        ;low end of screen kernel LSB
         bcc ccih03            ;not interrupted
;
         bcs ccih05            ;kernel was interrupted, can't display
;
ccih02   cmp #>scrnkerh        ;high end of screen kernel MSB
         bcc ccih05            ;in kernel, can't display
;
         bne ccih03            ;display allowed
;
         cpy #<scrnkerh        ;high end of screen kernel LSB
         bcc ccih05            ;in kernel, can't display
;
         beq ccih05            ;ditto


The above code fragment is from Clock-Calendar 128, which is able to drive a date and time display on a static status line on the 80 column screen via interrupts.  The stack-sniffing is a process of retrieving a copy of the PC values from the stack and comparing them to the screen kernel range in which VDC access would occur.  If it is determined that that address range was interrupted, CC128 skips display update to avoid disturbing any VDC register setup that was in progress at the time of the interrupt (the branch to CCIH05).  If the interrupted code is not in the screen kernel range, CC128 assumes it's safe to write to the VDC (CCIH03).

It's important to understand that a technique as illustrated above will only work if the interrupted program manipulates the VDC via the screen kernel routines.  If the program uses its own code to directly access the VDC and ignores the screen kernel, stack sniffing won't work unless told about the address range of the direct-access code.

Notice how none of the above code contains "magic numbers."  As I've said in the past, only an amateur with poor programming habits buries magic numbers and addresses within the source code.  It all should be assigned to meaningful label names at the beginning of the program.  In the case of CC128, a separate .INCLUDE file contains those definitionsâ€"I copied them into the above example for your benefit.
x86?  We ain't got no x86.  We don't need no stinking x86!

stiggity

BDD:
I understand your routine, and the labeling make it very easy to read. Not saying what i read is 100% and instantly understood. Heres a "newb" doozie 4 ya.. where would i add your snippet in my own program?

ccih05 is pointing towads a conflict, and needs exited, cant display.. where would i go??

cciho3 , everything is fine, continue... continue to where..

I guess what im asking is, would this routine be tied into my clock IRQ (which was hand written), or stand-a-lone, and if it is tied into the IRQ code, where should i perform the said checking..

I really appreciate the help..
-Steve

BigDumbDinosaur

Quote from: stiggity on July 30, 2010, 07:52 AM
BDD:
I understand your routine, and the labeling make it very easy to read. Not saying what i read is 100% and instantly understood. Heres a "newb" doozie 4 ya.. where would i add your snippet in my own program?

ccih05 is pointing towads a conflict, and needs exited, cant display.. where would i go??

cciho3 , everything is fine, continue... continue to where..

I guess what im asking is, would this routine be tied into my clock IRQ (which was hand written), or stand-a-lone, and if it is tied into the IRQ code, where should i perform the said checking.
I'm going to leave some of that up to your imagination.  Put your brain to work and figure it out.  Hint: since the code is meant to resolve a potential display conflict within your IRQ handler, just where would you put the code?  Also, would you insert that code as an inline function or within a subroutine?  Don't forget you'll need to store the result of the stack sniff in a flag somewhere for later use.  Figure it out!  You won't learn anything if I do it for you, which I won't.
x86?  We ain't got no x86.  We don't need no stinking x86!

stiggity

BDD:
Well your efforts are in vain, becuase i have no clue where to insert your fragment. I tried adding it as the main IRQ and it didnt work, and i dont know where to branch too or anything. I appreciate the assistance, and the time it took you to type your replies in, but when you throw out something as tall as that, and expect someone to get it working... i wish i could. Ill look at it some more.

-Steve

stiggity

This is how im understanding it so far..

hwstack  =$0100                ;MPU hardware stack
scrnkerl =$c53c                ;screen kernal low end
scrnkerh =$ce4c                ;screen kernal high end               
stakdpth =7                    ;stack sniff depth
;
;    determine if screen kernel was interrupted...
;
CLK sei
  lda  #<ccih01
  sta  $0314
  lda  #>ccih01
  sta  $0315
  cli
rts



ccih01   tsx                   ;get stack pointer
         lda hwstack+stakdpth,x
         ldy hwstack+stakdpth-1,x
         cmp #>scrnkerl        ;low end of screen kernel MSB
         bcc ccih03            ;not interrupted
         bne ccih02            ;not at low end, check high
         cpy #<scrnkerl        ;low end of screen kernel LSB
         bcc ccih03            ;not interrupted
         bcs ccih05            ;kernel was interrupted, can't display
ccih02   cmp #>scrnkerh        ;high end of screen kernel MSB
         bcc ccih05            ;in kernel, can't display
         bne ccih03            ;display allowed
         cpy #<scrnkerh        ;high end of screen kernel LSB
         bcc ccih05            ;in kernel, can't display
         beq ccih05            ;ditto

ccih03 jmp clock1
ccih05 jmp nope12

CLOCK1 beginning of my TOD clock routine..
nope12 jmp $FA65 ;return to basic..

stiggity

Man...
All i was asking was a little help witi m y clock routine ties into the IRQ. I read your source, but there are lables being "BIT" and "BEQ" and alot more that i have no clue what values are supposed to be there. And nowhere in that entire fragment did it say $314/$315. I could post my clock routine.. the source isnt too bad. I just _NEED_ to know what to do so the IRQ clock can run in harmony with the rest of the VDC screen. Not to check if im in 40columns, or if the screen is blanked, etc. In no way should you take offense to my above rant. You are one of the most methodical and intelligent programmers out there. U have to remember, this 128 BBS im hacking together is only my 2nd ML project, and its not pure ML either. Its mostly basic, with all of the heavily used/needed routines written in assembler. Maybe u coud have a change of heart and actually help me, instead of confuse me. I just cant take an example source snippet, and automatically enter it into my own code. At first i would have to understand it. And the source u just posted is 100% un-understandable to a beginner. And No, i am not sticking to basic. If i wrote an okay BBS prg for the 64, i dont see why i couldnt do the same for the 128. I figured out all of my lightbar screen locations, color codes, reading from the vdc etc.. im sure i will be able to get this clock working.. even if i need a little aid from the guru's.. eh??

-Steve

cbmguy

Hey there.  I'm working on a mouse driver for the VDC--which came to be because of another project that I'm programming; it'll never get finished if I keep this up...  anyways...  I came up with the same sort of thing that you are describing: misc characters dumped on the VDC while printing during interrupts.  I don't have my source around (I'm half way across the country at the moment) but maybe this can point you in the correct direction. I waited for the VDC to be finished with it's chores first and then I allowed my driver to execute and print to the screen.  In a more specific way of saying, I waited for the stack to have an address that pointed to the vdc wait loop.  When that address was true, I then allowed the driver to print to the VDC.  I'm sure that there's more ways to do this, but this was a quick and effective way of displaying to the VDC during an IRQ without screwup the VDC's own housekeeping.  Sorry, but I cannot remember the exact address for the VDC wait loop at the moment.

If I had more time I'd put some effort into making this a little more easier to read and follow.  I hope this gets you on the right track.

C

stiggity

cbmguy:
It sounds like your a much better programmer than I am. Possibly, when u get back to your source code, u could post a small snippet, and i can see what your talking about.. but yeah, that does sound like whats going on with my code..
-Steve

cbmguy

#19
It might be a week or more before I get back.  Just take what I've said and do a little reading on the VDC in the C128 PRG.  You'll find out that you'll learn even more things--better assembler code even--then what you thought.  All the driver does before it get's the go-ahead to do it things is monitor the stack for the address and if it's the correct address, then it will execute.  Please, just do a little reading in the RPG (like I had).  You have the answer (vdc wait/idle loop address), just head to some literature and investigate.

Let me know how you make out.

Cheers,

C

mapping the c128 is also invaluable and has a specific chapter devoted to the subject that we're talking about here.