Main Menu

Z80 op-codes

Started by baggey, November 10, 2012, 12:05:31 PM

Previous topic - Next topic

baggey

Well been busy researching the z80 index.

As im writing an emulator with an incorporated disambler. Ive been browsing z80 reference manuals etc.

I didn't realise i was going back to 2's complement, logic gates, Lsb and Msb and then need to throw all this together. Just to update the flag register!

At the same time im getting to grips with memory banks and pointers, and finaly realise its just peeking and pokeing  :P

Some of you might be yawning by this stage!

But im completely hooked!  :o

Its brung back teenage memory's of old computer games, whilst also realising that some of the stuff i did in college. Has at last become useful.

God i need to get a life!? But on the other hand i love this one!  ;D 

Baggey
Jesus was only famous because of his dad

micky4fun

Hi all

keep up the good work baggey , looks like you are getting right stuck in there mate

mick :)

baggey

Any one with Z80 OP-code knowlegde?

I need someone to clarify if ive got this one right?

PlayBASIC Code: [Select]
op_243:  // DI

nxtpc=1

if monitormode=true

if hex_or_dec = false
// Decimal representation
text 1200,placeopcodeslne,digits$(pc,5)
text 1270,placeopcodeslne,digits$(op_byte,3)
text 1460,placeopcodeslne,"DI"
else
// Hex representation
text 1200,placeopcodeslne,right$(hex$(pc),4)
text 1270,placeopcodeslne,right$(hex$(op_byte),2)
text 1460,placeopcodeslne,"DI"
endif
endif

// DI disables the maskable interrupt by resetting the interrupt enable flipflops
// (IFF1 and IFF2). Note that this instruction disables the maskable
// interrupt during its execution.

if execute=true
intIFF1 = 0
intIFF2 = 0
intIM = 0
; no flags affected
fs = fs
fz = fz
f5 = f5 ; Not used
fh = fh
f3 = f3 ; Not used
fpv = fpv
fn = fn
fc = fc

exeTstates = 4
endif

return ;done note check interupt registers



Baggey
Jesus was only famous because of his dad

kevin


what instruction is it meant to be ?

baggey

DI

It disables all interupts and the two flip-flop registers. Which i can only assume, is to do with the Z80 chip it's self?

I know there's an interupt IM register and it can only be 1 or 0.

I think there related but dont know how?

The Z80 flip-flops are IFF1 and IFF2. I think these are only 1 or 0 again! Hi or Low outputs.

It may be away of controlling external peripherals connected to the back of the Spectrum?

So possibly. I dont need to worry about them, if im not emulating them ::)

Baggey
Jesus was only famous because of his dad

baggey

#5
Yippy!  :D

Ive finally come across some rom code. Which is going to turn the border white OUT (254),7

So now i need that bit of code for copying an image into another one! Full screen should be easy.

But because of the way ive set the GUI up. ie ive got curved edges around the border part?

I think im going to need an image to draw over the exact same size. But the corner's. I think need to be a maskable colour. So i dont destroy the GUI corners?

Any ideas?

///////////

Well the approach i thought of has worked!

When i created the GUI skeleton in memory. I took an image just slightly bigger. This was then edited in a paint program.
so when i build the screen display :-

I firstly place a CLS image with the colour i want.
Then.
Place the border GUI frame on top off that, Then the screen image!

Its like making a Graphical Sandwich  :P

This works a treat  ;D

The thing is sometimes, something's. Might be simple as, to somebody. But, When your not used to thinking in a certain way. Something's might seem harder than it actualy is  ::)
What do they call it? Ah yeah. THINKING OUT SIDE THE BOX!

///////////

Baggey

Baggey
Jesus was only famous because of his dad

baggey

#6
CP H

Compare CP H with the accumulator.

Effect is :-

If H=A then ???? do something ????

Because were effecting, the Flag register only! For the outcome. Also no change to the accumulator or the H register either!

PlayBASIC Code: [Select]
op_188:  // CP H

nxtpc=1

if monitormode=true

if hex_or_dec = false
// Decimal representation
text 1200,placeopcodeslne,digits$(pc,5)
text 1270,placeopcodeslne,digits$(op_byte,3)
text 1460,placeopcodeslne,"CP H"
else
// Hex representation
text 1200,placeopcodeslne,right$(hex$(pc),4)
text 1270,placeopcodeslne,right$(hex$(op_byte),2)
text 1460,placeopcodeslne,"CP H"
endif
endif

// The contents of the H are compared with the contents of the Accumulator.
// If there is a true compare, the Z flag is set. The execution of
// this instruction does not affect the contents of the Accumulator

if execute=true

;S is set if result is negative; reset otherwise
;Z is set if result is zero; reset otherwise
;H is set if borrow from bit 4; reset otherwise
;P/V is set if overflow; reset otherwise
;C is set if borrow; reset otherwise

fs = False
fz = False
f5 = False
fh = False
f3 = False
fpv = False
fn = true ; is set
fc = False

endif
exeTstates = 4
return



This is were ive got with it?

I need to do a subtraction in Two's complement and i suppose the only way to Check each bit is. And 6 times as two flags arn't used. Ie with a For and next loop?
OR
Possibly 4 IF statements?

I can do, either! But its the Quickest approach needed!

Here's a useful video for SUBTRACTION! In 2's Complement.

http://www.youtube.com/watch?feature=player_detailpage&v=rtMU2WWtQCg

I need the subtraction i think? As,

If two numbers are the same the result is zero!
If after the subtraction, the result is a remainder or a positive result!
If after the subtraction, the result is a remainder with bit 7 set. We have a negative result!
If Bit 3 has a one due to the subtraction. We have the Halve CARRY being reset!

So. If statements seem to be the way anyway's. Just need to know wether this is the approach needed. At machine level!? ANYONE?

Kind regards Baggey

///////////

I think this is the outcome!? But not entirely convinced?

PlayBASIC Code: [Select]
op_188:  // CP H

nxtpc=1

if monitormode=true

if hex_or_dec = false
// Decimal representation
text 1200,placeopcodeslne,digits$(pc,5)
text 1270,placeopcodeslne,digits$(op_byte,3)
text 1460,placeopcodeslne,"CP H"
else
// Hex representation
text 1200,placeopcodeslne,right$(hex$(pc),4)
text 1270,placeopcodeslne,right$(hex$(op_byte),2)
text 1460,placeopcodeslne,"CP H"
endif
endif

// The contents of the H are compared with the contents of the Accumulator.
// If there is a true compare, the Z flag is set. The execution of
// this instruction does not affect the contents of the Accumulator

if execute=true

if rega-regh<0 ; S is set if result is negative; reset otherwise
fs=true
else
fs=false
endif

if rega-regh=0 ; Z is set if result is zero; reset otherwise
fz=true
else
fz=false
endif

f5 = False ; Not used

areg=rega and 8
hreg=regh and 8
if areg=0 and hreg=1 ; H is set if borrow from bit 4; reset otherwise
fpv=true
else
fpv=false
endif

f3 = False ; Not used

if rega-regh<-255 ; P/V is set if overflow; reset otherwise
fpv=true
else
fpv=false
endif

fn = true ; is set

if rega-regh<-255 ; C is set if borrow; reset otherwise
fpv=true
else
fpv=false
endif

endif
exeTstates = 4
return ; done for now ?????



Im also thinking there are four rega-regh statements. Im learning that this redundancy.

So. It might be quicker if i used ans=rega-regh then substitute this in the three corresponding equations, Like so!

PlayBASIC Code: [Select]
op_188:  // CP H

nxtpc=1

if monitormode=true

if hex_or_dec = false
// Decimal representation
text 1200,placeopcodeslne,digits$(pc,5)
text 1270,placeopcodeslne,digits$(op_byte,3)
text 1460,placeopcodeslne,"CP H"
else
// Hex representation
text 1200,placeopcodeslne,right$(hex$(pc),4)
text 1270,placeopcodeslne,right$(hex$(op_byte),2)
text 1460,placeopcodeslne,"CP H"
endif
endif

// The contents of the H are compared with the contents of the Accumulator.
// If there is a true compare, the Z flag is set. The execution of
// this instruction does not affect the contents of the Accumulator

if execute=true

ans=rega-regh

if ans<0 ; S is set if result is negative; reset otherwise
fs=true
else
fs=false
endif

if ans=0 ; Z is set if result is zero; reset otherwise
fz=true
else
fz=false
endif

f5 = False ; Not used

areg=rega and 8
hreg=regh and 8
if areg=0 and hreg=1 ; H is set if borrow from bit 4; reset otherwise
fpv=true
else
fpv=false
endif

f3 = False ; Not used

if ans<-255 ; P/V is set if overflow; reset otherwise
fpv=true
else
fpv=false
endif

fn = true ; is set

if ans<-255 ; C is set if borrow; reset otherwise
fpv=true
else
fpv=false
endif

endif
exeTstates = 4
return ; done for now ?????




Baggey
Jesus was only famous because of his dad

kevin


A Boolean expression is better option for setting a flag..

So a block like this,
PlayBASIC Code: [Select]
if ans<0   ; S is set if result is negative; reset otherwise
fs=true
else
fs=false
endif




becomes

PlayBASIC Code: [Select]
  fs=ans<0





baggey

#8
Thanks for the tip kevin! Its the little things that make the big differences.

Im going to have a bit more free time now "Celebrity get me out of here" is finished.

Ive been working on a Z80 Simulator.

Where the coding is, the same as the playbasic Speecy. So, ill be able to cut and paste into the Emulator.
I shall release the code so it can be worked on!

I Suppose here is as good as anywhere?

Im hoping if any one whats to add an instruction, they can. The general criteria will be. POST the code of the instruction they've worked on. Ill check it and add it to the "Speccy Playbasic Emulator!" If they submit a few instructions there name will be mentioned in the credits  ;)

If people want to participate. The sooner will have, the "playbasic Speccy Emulator" Working  ;D
Jesus was only famous because of his dad

kevin


OK, I'll volunteer for the NOP instruction.  :)

Dunno how much help anybody here would be really. Know a number of people still messing around with legacy demo programming (8/16 bit systems), but can't think of anybody that fluent in Z80.


baggey

#10
Hmm, Well anyway here it is  :D

Extract Zip to "c:\"

Ill be interested to see how many hits it gets aswell  ::)
If only it was the same for drop box! You just don't know how many times its been downloaded?

Oh yeah! If you see any bottle necks or improvements. Plz let me know  ;)
Kind regards Baggey
Jesus was only famous because of his dad

kevin

#11
 Had a bit of look-see,  seems to be further on than i'd imagined in terms of the frame work.   Not too sure why the disassembler and execution stuff are together, the first thing i'd do would be separate them.    To decode the opcode strings, i'd use probably use some type either completely precomputed tables, or some form of table with mark up instructions to decode.

I'm not sure of the plans for this code,  but to me there seems that the Execute_Opcode() function contains a lot of fixed overhead that i'm guessing isn't really necessary.  If you look at the routine bellow,  then to run one opcode it's falling through  the same number of compares (IF statements) even when the match is found.   So imagine the cost of calling Execute_opcode()  10,000-> 20,000 times and those little things soon magnify into very big things.

PlayBASIC Code: [Select]
psub Execute_opcode()

monitormode=false

prefix = peekbyte(savepc)

if prefix <> 203 or 221 or 237 or 253 then prefixtype = 0 ; 00 codes

if prefix = 203 then prefixtype = 1 ; CB codes
if prefix = 221 then prefixtype = 2 ; DD codes
if prefix = 237 then prefixtype = 3 ; ED codes
if prefix = 253 then prefixtype = 4 ; FD codes


if prefixtype = 0
oo_opcode(prefix)
redtstate=exetstates
endif

if prefixtype = 3
prefix = peekbyte(PCptr+pc+1)
ed_opcode(prefix)
redtstate=exetstates
endif

if prefixtype = 4
prefix = peekbyte(PCptr+pc+1)
fd_opcode(prefix)
redtstate=exetstates
endif

if defb<>1
pc=pc+defb
defb=1
redtstate=exetstates
endif

clockcyclescounter=clockcyclescounter+redtstate
instotal++
pccounter=pccounter+nxtpc
monitormode=true
execute=false

endpsub






  So rather than falling through looking for a match, when you find a match jump to out code..  

  Example ONLY.

PlayBASIC Code: [Select]
psub Execute_opcode()

monitormode=false

prefix = peekbyte(savepc)

; what is this meant to doi
if prefix <> 203 or 221 or 237 or 253 then prefixtype = 0 ; 00 codes

if prefix = 203

; do stuff here
goto DONE

endif


if prefix = 221

; do stuff here
goto DONE
endif

if prefix = 237

; do stuff here
goto DONE
endif

if prefix = 253

; do stuff here
goto DONE
endif


oo_opcode(prefix)
redtstate=exetstates

DONE:
if defb<>1
pc=pc+defb
defb=1
redtstate=exetstates
endif

clockcyclescounter=clockcyclescounter+redtstate
instotal++
pccounter=pccounter+nxtpc
monitormode=true
execute=false


endpsub





   what is this meant to do BTW ?
   
   if prefix <> 203 or 221 or 237 or 253 then prefixtype = 0 ; 00 codes

    It's comparing if  prefix is <> to 203, then it's or'ing 203 , or'ing 221 ,or'ing 253.. So the expression will  always be true.  


    in the opcode decoder functions.  You can actually use ON variable GOTO  rather than Gosub.    Saving at least one stack pop every opcode.  


PlayBASIC Code: [Select]
    oo_opcode(op_byte)


psub oo_opcode(op_byte)

on op_byte goto op_0,op_1,op_2,op_3


op_0:
return

op_1:
return

op_2:
return

op_3:
return

etc etc

endpsub










baggey

Quotewhat is this meant to do BTW ?
   
    if prefix <> 203 or 221 or 237 or 253 then prefixtype = 0 ; 00 codes

     It's comparing if  prefix is <> to 203, then it's or'ing 203 , or'ing 221 ,or'ing 253.. So the expression will  always be true. 


     in the opcode decoder functions.  You can actually use ON variable GOTO  rather than Gosub.    Saving at least one stack pop every opcode. 

Write. I understood this to an english sentence rather than a logic gate expression?

ie, The instruction im examining is "prefix". So im looking for the "case".
     As im stepping through the code. If i see prefix being either 203,221,237,253. I must have no prefix instruction thus selecting prefixtype=0, using only the 00_code table?

I hope that makes sence? It does to my logic ::)

I am building the instruction up to see what it is. As if you execute from another PC instruction! You end up with an entirely different program!?

Kind regards Baggey
Jesus was only famous because of his dad

kevin

   
PlayBASIC Code: [Select]
   ; set it some value that's not 203
Prefix=123
print hex$(prefix <> 203 or 221 or 237 or 253)

; set it to 203
Prefix=203
print hex$(prefix <> 203 or 221 or 237 or 253)

Sync
waitkey




   
  It doesn't matter what prefix is, it'll always return the same value, since this is one expression.  I suspect you want multiple comparisons, but that not what your doing.


   That'd be,

   print hex$(prefix <> 203 or prefix <>221 or prefix <>237 or prefix <>253)

   but it's still a flawed expression,  as when if Prefix equal to 203, it'll be not equal to 221 or 237 or 253 and return one every time. 


PlayBASIC Code: [Select]
   Prefex=100 
print hex$(prefix <> 203 or prefix <>221 or prefix <>237 or prefix <>253)


Prefex=203
print hex$(prefix <> 203 or prefix <>221 or prefix <>237 or prefix <>253)

Sync
waitkey




baggey

#14
Very interesting!?

ive omitted it from

PlayBASIC Code: [Select]
psub Execute_opcode()

monitormode=false

prefix = peekbyte(savepc)
prefixtype=0
;if prefix <> 203 or 221 or 237 or 253 then prefixtype = 0 ; 00 codes
if prefix = 203 then prefixtype = 1 ; CB codes
if prefix = 221 then prefixtype = 2 ; DD codes
if prefix = 237 then prefixtype = 3 ; ED codes
if prefix = 253 then prefixtype = 4 ; FD codes


if prefixtype = 0
execute=true
oo_opcode(prefix)
redtstate=exetstates
endif

if prefixtype = 3
prefix = peekbyte(PCptr+pc)
ed_opcode(prefix)
redtstate=exetstates
endif

if prefixtype = 4
prefix = peekbyte(PCptr+pc+1)
fd_opcode(prefix)
redtstate=exetstates
endif

if defb<>1
pc=pc+defb
defb=1
redtstate=exetstates
endif

clockcyclescounter=clockcyclescounter+redtstate
instotal++
pccounter=pccounter+nxtpc
monitormode=true
execute=false

endpsub



And yeah it makes no difference to the EXECUTE stage!

Finishing with

PlayBASIC Code: [Select]
psub Execute_opcode()

monitormode=false

prefix = peekbyte(savepc)
prefixtype=0
;if prefix <> 203 or 221 or 237 or 253 then prefixtype = 0 ; 00 codes
if prefix = 203 then prefixtype = 1 ; CB codes
if prefix = 221 then prefixtype = 2 ; DD codes
;if prefix = 237 then prefixtype = 3 ; ED codes
;if prefix = 253 then prefixtype = 4 ; FD codes


if prefixtype = 0 ; No Prefix
oo_opcode(prefix)
redtstate=exetstates
endif

if prefix=237 ; ED codes
prefix = peekbyte(PCptr+pc)
ed_opcode(prefix)
redtstate=exetstates
endif

if prefixtype=253 ; FD codes
prefix = peekbyte(PCptr+pc+1)
fd_opcode(prefix)
redtstate=exetstates
endif

if defb<>1
pc=pc+defb
defb=1
redtstate=exetstates
endif

clockcyclescounter=clockcyclescounter+redtstate
instotal++
pccounter=pccounter+nxtpc
monitormode=true
execute=false

endpsub



Ive implemented the goto instead of the gosub!

I can actually feel the program responding quicker  ;) Ie, more responsive.

Ive now also tried omitting it in place_opcode() but theres a flaw somewhere the fist line being printed flickers????? as you step through!

Ive had a look and i dont understand why it does this! So ive left that part as it was  ???

Baggey
Jesus was only famous because of his dad