|
Post by mirkosoft on Sept 11, 2014 18:48:16 GMT
Hi!
I created simple Z80 CPU check if is available/accessible to avoid conflicts with SuperCPU
All is ok, output too, but after RTS it jumps to MONITOR and pointer shows $00ba, in case of turned on SCPU it outputs BREAK text in forever loop. This behavior after succesfull code run I don't understand. Can anybody explain it me?
Here's code:
*=$2000
start:
nop ; this will be later flag lda $ff00 ; store RAM config
pha ; to stack
sei ; disable interrupts
lda #$60 ; store RTS (LD H,B) instruction for Z80 mode start
sta $ffee ; where PC points
lda #$c3 ; store JP
sta $ffef ; to next byte
lda #$50 ; lo-byte of jump
sta $fff0 ; to next byte
lda #$20 ; hi-byte of jump
sta $fff1 ; to next byte
lda #$3e ; select RAM config for Z80
sta $ff00 ;
lda $d505 ; store mode
pha ; to stack
lda #$b0 ; set Z80 mode
sta $d505 ; this instruction deactivates 8502 and jumps by Z80 PC to $ffee
nop ; when is 8502 again activated 8502 PC points here
lda #$00 ; set bank 15
sta $ff00 ;
wri: lda $2000 ; read Z80 flag ($ea - inactive / $31 - active) cmp #$ea
bne skip
lda #$30
skip: jsr $ffd2 ; print character (universal C128/C64/C+4)
lda #$ea
sta $2000
rts ; here it ends and after RTS execution it jumps/break to $00ba
*=$2050
.byte $3e, $31, $32, $00, $20, $3e, $3e, $32, $00, $ff, $c3, $e0, $ff
; Z80 Code ; ; LD A, $31 ; set Z80 flag (character "1")
; LD ($2000),A ; as active
; activate 8502:
; LD A, $3e ; store memory
; LD ($ff00),A ; configuration
; JP $ffe0 ; activate 8502
|
|
|
Post by hydrophilic on Sept 12, 2014 6:03:34 GMT
You normally do not want to inject a Z80 'RET' opcode (same as 6502 RTS). Instead just code a Z80 'JP' opcode (same as 6502 JMP). For example (based on your prior post)...
Also in your original post you did 2 (two) of PHA but only 0 (zero) of PLA... that will crash the system! In the revised version (below) I removed a PHA and added a PLA. So now 1 PHA and 1 PLA... everything is balanced!
*=$2000 start: nop ; this will be later flag lda $ff00 ; store RAM config pha ; to stack *** note 1 PHA *** sei ; disable interrupts
;prepare Z80 lda #$c3 ; store JP sta $ffee ; to next byte lda #$50 ; lo-byte of jump sta $ffef ; to next byte lda #$20 ; hi-byte of jump sta $fff0 ; to next byte
;invoke Z80 lda #$3e ; select RAM config for Z80 sta $ff00 ; lda $d505 ; store mode ;;;pha DO NOT SAVE TO STACK... Z80 will write $d505 to (re)activate 6502! lda #$b0 ; set Z80 mode sta $d505 ; this instruction deactivates 8502 and jumps by Z80 PC to $ffee nop ; when is 8502 again activated 8502 PC points here
;Z80 has finished, resume 6502 code... ;;lda #$00 WRONG... the MMU was saved on the stack before pla ;recall MMU *** note 1 PLA *** sta $ff00 ; wri: lda $2000 ; read Z80 flag ($ea - inactive / $31 - active) cmp #$ea bne skip lda #$30 skip: jsr $ffd2 ; print character (universal C128/C64/C+4) lda #$ea sta $2000 rts ; here it ends
I haven't tested it, but I think it should work. Any questions? Just ask!
Edit Note you might re-write the Z80 code so it acts like a subroutine. If you did that, RET opcode would be fine... but that should be a different topic!
Anyway, it is always important that you have same number of push (PHA or PHP) and same number of pull (PLA or PLP) in normal code, like shown above (1 byte push and pull... the MMU $ff00 configuration). Your original code will crash because the stack is corrupted (number of Push not equal number of Pull).
Ummm... if you get fancy, you can violate this rule... 2 pushes can be balanced with one RTS... or 3 pushes can be balanced with RTI... but that would be yet another topic!!
|
|
|
Post by VDC 8x2 on Sept 13, 2014 0:17:57 GMT
Does the z80 use the same stack area?
|
|
|
Post by hydrophilic on Sept 13, 2014 6:51:57 GMT
The Z80 stack is programmable. You can set it anywhere in the 64K range of memory. Of course it *should* be set to an area in Common RAM, otherwise calling code in another bank will be virtually impossible. Also the ROM does not set the stack pointer! So you (the programmer) must set it... or rely on the hardware reset value (which I *think* is $0000 which would wrap to high-RAM and clobber 6502 vectors).
|
|
|
Post by mirkosoft on Sept 13, 2014 8:16:22 GMT
Hi Robert!
I tried your correction. OK, now it crashes not but in 128 mode it outputs flag then ready and computer hangs until I hit STOP+RESTORE. In 64 mode or test on +4 it works correctly. Really don't see problem to rewrite Z80 code to use subroutine, but I see not reason why - please explain it me better.
Miro
|
|
|
Post by gsteemso on Sept 21, 2014 23:39:10 GMT
Really don't see problem to rewrite Z80 code to use subroutine, but I see not reason why - please explain it me better. I think I know this one. When you switch to or from Z80 mode, the process of so doing does not write a return address to the stack — it just toggles a line coming out of the MMU, such that whatever CPU has just become active resumes execution at wherever its Program Counter was pointed (as I understand matters, this would usually be in the OS routine intended by Commodore to handle the switch). Thus, if you end with any type of “return to stacked address” instruction, a value is popped from the stack that was never placed there in the first place, sowing the seeds of chaos and confusion.
|
|
|
Post by mirkosoft on Sept 22, 2014 17:01:15 GMT
Hi! It's only in rhis case - I'm programming in Z80 mode and toggle between modes was never problem. Special is this bit of code. Z80 programming and use with C128 is clear and easy, this case confuses me.
Miro
|
|
|
Post by gsteemso on Sept 25, 2014 4:23:35 GMT
Sorry for the unhelpful reply, I misread your follow-up question. I suppose the most relevant question I have from this point is, “How are you getting to this code?” …or to put it more directly, “Where does that RTS at the end lead to?” Can’t really answer you without seeing that.
Also, I know it doesn’t really matter, but I noticed that the part where Hydrophilic turns this:
lda $d505 ; store mode pha ; to stack
into this:
lda $d505 ; store mode ;;; pha DO NOT SAVE TO STACK... Z80 will write $d505 to (re)activate 6502!
…could all (both instructions) just be deleted entirely, since nothing need be done with the value at that point.
After looking at the Compute!’s Mapping the Commodore 128 synopsis of register $D505, I further observe that setting it to a fixed value ($B0 in this case) is only appropriate for certain types of code. If you were to use this in serious (“production”?) software while some other code was running that needs any of the other 5 usable bits in that register, you will either interfere with whatever the other code was doing, or disable it entirely. Neither is likely to be what was intended. My recollection of the minutiæ of 6502 instructions is hazy, but I believe that:
lda #$b0 ; set Z80 mode sta $d505 ; this instruction deactivates 8502 and jumps by Z80 PC to $ffee
…should in some use-cases be replaced by something like:
LDA #$FE ; bitmask to set processor selection bit to 0=Z80 AND $D505 ; disable 8502, resuming Z80 execution where it left off (usually at $FFEE) Can anyone confirm that I did that right? Until I got my C128 I didn’t even own a machine language monitor, never mind an actual assembler (well, not one where I had any way to get the object code into a Commodore, anyway), so my knowledge in this area, unfortunately, tends to be mostly theoretical.
|
|
|
Post by gsteemso on Sept 25, 2014 4:40:32 GMT
I guess another way to do that last bit would be:
LDA #$01 ; bitmask for CPU selection bit: currently 1 for 8502, 0 means Z80 EOR $D505 ; toggle it to Z80 state
This way at least has the advantage of not needing to work in negative logic, as is required with a logical AND.
|
|
|
Post by hydrophilic on Sept 26, 2014 7:36:28 GMT
Yeah, what gsteemso said!! The lines to enable/disable Z80 (that I posted above) are based on your (Mirkosoft) code... but like gsteemso said, you can eliminate them (for efficiency). Also, gsteemso's suggestion of "LDA #1 / EOR $D505" is very elegant. (P.S. please forgive me, Gsteemso, if I adopt your code in the future without attribution.... it seems so natural after reading your post that I may not remember to give you proper credit)
|
|