Z80 emulation

If you have any questions on programming, this is the place to ask them, whether you're a newbie or an experienced programmer. Discussion on programming in general is also welcome. We will help you with programming homework, but we will not do your work for you! Any porting requests must be made in Developmental Ideas.
User avatar
Christuserloeser
Moderator
Moderator
Posts: 5941
Joined: Thu Aug 28, 2003 12:16 am
Location: DCEvolution.net
Has liked: 6 times
Been liked: 0
Contact:

Post by Christuserloeser » Tue Jul 06, 2004 9:03 pm

:o Thank you, Sanchez, Heliophobe, Sayten and DcSteve.

That's such a great moment... Image

Hope that it helps Stef D as much as I think.


Chris
Insane homebrew collector.
doragasu
DCEmu Cool Poster
DCEmu Cool Poster
Posts: 1048
Joined: Thu May 16, 2002 5:01 pm
Location: Madrid, Spain
Has liked: 0
Been liked: 0

Post by doragasu » Wed Jul 07, 2004 1:49 am

Christuserloeser wrote:Hope that it helps Stef D as much as I think.
I think Stef. is not going to finish it as he wrote he doesn't intend to write in SH4 ASM, but let him write here :lol:
User avatar
Stef.D
DCEmu Respected
DCEmu Respected
Posts: 114
Joined: Wed Oct 15, 2003 1:46 am
Has liked: 0
Been liked: 0
Contact:

Post by Stef.D » Wed Jul 07, 2004 2:05 am

DcSteve wrote:Sayten himself gave me the link to his unfinished z80 sh4 core. It has a basic exec loop, and has ~ 1/2-2/3 of the opcodes implemented. He didn't implement opcodes as he needed them. He took the opcode list for the z80 and started at the top and worked his way down. While he's tested what he's written and it seems to work ok, he hasnt actually used the core in anything real. Its not pretty or fast. Just a basic interpreted cpu emu. He figured max speed on a dc was about 20MHz. Here is his work.

http://www.wolfnet.org/~jkf/dc/src/dc_z80.tar.gz
Thanks for the link :) the core is really advanced but 20 Mhz isn't that much for an ASM core. It's a good base for anyone who want to do a fast Z80 asm core, we can easily improve speed of this core by replacing the functions pointers table by a simple jump table and remove the call for each fetch :) but right now, this core shouldn't be really faster than actual C core.

On my side, i prefer to stay with C, i believe it's possible to have a 40/50 Mhz Z80 even with a C core ;)
Warmtoe
DC Developer
DC Developer
Posts: 453
Joined: Thu May 16, 2002 8:29 am
Location: ice88's house
Has liked: 0
Been liked: 0
Contact:

Post by Warmtoe » Wed Jul 07, 2004 7:41 am

Stef,

I made an initial stab at doing z80 work with a jump table - it's working but I have only implemented a fraction of the opcodes at the moment .

How do you remove the call for each fetch though? I will carry on with my hack - I'm sure yours will be much better - but I don't see how you can eliminate the fetch. One thought I had is to use the much-maligned cache to speed things up - by pointing it at the location that represents the current PC for the z80 - will that help?

Anyway - any insight!
Rev. Layle
Insane DCEmu
Insane DCEmu
Posts: 190
Joined: Sun Jun 27, 2004 8:35 pm
Location: stillwater, ok
Has liked: 0
Been liked: 0
Contact:

Post by Rev. Layle » Wed Jul 07, 2004 8:42 am

looking at Sayten's code - isn't making a global pointer to a struct, allocating memory THEN access the stuct pointers members everytime you need to access registers or memory or ports a bit wasteful. i mean every time you access the variable "z80" it must be dereferenced and the the offset of the memeber in the struct must be calculated from the resulting address. THEN port_read and port_write are put into function pointers. depending on how often they are called, the more defrefencing for EACH call as well as the overhead for the function call itself.
User avatar
Stef.D
DCEmu Respected
DCEmu Respected
Posts: 114
Joined: Wed Oct 15, 2003 1:46 am
Has liked: 0
Been liked: 0
Contact:

Post by Stef.D » Wed Jul 07, 2004 8:56 am

Warmtoe wrote:Stef,

I made an initial stab at doing z80 work with a jump table - it's working but I have only implemented a fraction of the opcodes at the moment .

How do you remove the call for each fetch though? I will carry on with my hack - I'm sure yours will be much better - but I don't see how you can eliminate the fetch. One thought I had is to use the much-maligned cache to speed things up - by pointing it at the location that represents the current PC for the z80 - will that help?

Anyway - any insight!
As i done in C68K : in a standard CPU emulator, you store the current PC of emulated cpu in a variable (register is better) we can just call "PC" :)
Then when you need to fetch the next opcode (and opcode parameter) you'll have to read data at this address.
Since we execute code from this area, we can see it as a large memory space : RAM / ROM , this is the "fetch area".

Imagine we define fetch area as follow (for a Z80 CPU) :
0x0000-0x7FFF = rom_data
0xE000-0xFFFF = ram_data
(code can't be executed from IO port, that doesn't make sense.)

Well, the trick is that PC is equal to (cpu PC + fetch base)
Imagine we the following instruction : bra 0x450

with a conventionnal CPU core we only need to do :
...
NewPC = FetchWord;
PC = NewPC;
...

but here we'll do :

...
NewPC = FetchWord;
PC = FetchBase[NewPC >> X] + NewPC;
...

where FetchBase is a (0x10000 >> X) sized table containing Fetch base area (X can be 4-12, depending what we need).

Then when you need to fetch data, you only have to do :
data = *(u8*)PC; for byte
data = *(u16*)PC; for word
....

That make stuff a bit more complexe, since PC doesn't contain the real PC value, but it's a lot faster for fetch then ;)

My english is really limited, i hope you can understand my explainations.

Edit : That trick about PC can also be done on SP (stack pointer) since we *normally* use it only to store datas in memory area (no ports), but imo it doesn't worth the effort.
Last edited by Stef.D on Wed Jul 07, 2004 9:22 am, edited 2 times in total.
Rev. Layle
Insane DCEmu
Insane DCEmu
Posts: 190
Joined: Sun Jun 27, 2004 8:35 pm
Location: stillwater, ok
Has liked: 0
Been liked: 0
Contact:

Post by Rev. Layle » Wed Jul 07, 2004 9:00 am

does ">> 8" perform 8 shift instructions? or the does the SH4 have an instruction to move 8 bits in one instruction?
User avatar
Stef.D
DCEmu Respected
DCEmu Respected
Posts: 114
Joined: Wed Oct 15, 2003 1:46 am
Has liked: 0
Been liked: 0
Contact:

Post by Stef.D » Wed Jul 07, 2004 9:09 am

Rev. Layle wrote:does ">> 8" perform 8 shift instructions? or the does the SH4 have an instruction to move 8 bits in one instruction?
I wrote 8 because i often use 8 but it can be any other value (between 0 and 15)... SH4 support >>1, >>2, >>8, >>16 in 1 cycle as far i remember.
Rev. Layle
Insane DCEmu
Insane DCEmu
Posts: 190
Joined: Sun Jun 27, 2004 8:35 pm
Location: stillwater, ok
Has liked: 0
Been liked: 0
Contact:

Post by Rev. Layle » Wed Jul 07, 2004 9:11 am

cool - i learn something new everyday :)
DcSteve
Modder Of Rage
Modder Of Rage
Posts: 805
Joined: Mon Mar 18, 2002 12:41 pm
Location: Midwest
Has liked: 0
Been liked: 0
Contact:

Post by DcSteve » Wed Jul 07, 2004 11:01 am

warmtoe- how do you have sound working now? Does it still loop like it did in preview 3?
Check out the beats of rage community at http://borrevolution.vg-network.com/
Warmtoe
DC Developer
DC Developer
Posts: 453
Joined: Thu May 16, 2002 8:29 am
Location: ice88's house
Has liked: 0
Been liked: 0
Contact:

Post by Warmtoe » Wed Jul 07, 2004 11:16 am

DcSteve wrote:warmtoe- how do you have sound working now? Does it still loop like it did in preview 3?
It still sucks - I'm not going to release it until it sucks a lot less - don't fret, it will get out - but it's just not worth it at the moment. Remember too that others are working on bits for this:-

Stef. D is looking into the z80 emulation properly (unlike my hacking)
BlackAura has been looking at the graphics code some more.

It'll be worth the wait, trust me.
Rev. Layle
Insane DCEmu
Insane DCEmu
Posts: 190
Joined: Sun Jun 27, 2004 8:35 pm
Location: stillwater, ok
Has liked: 0
Been liked: 0
Contact:

Post by Rev. Layle » Wed Jul 07, 2004 11:38 am

how much memory mapped i/o and interrupts does the z80 in the genesis have to deal with?
Last edited by Rev. Layle on Wed Jul 07, 2004 11:44 am, edited 1 time in total.
DcSteve
Modder Of Rage
Modder Of Rage
Posts: 805
Joined: Mon Mar 18, 2002 12:41 pm
Location: Midwest
Has liked: 0
Been liked: 0
Contact:

Post by DcSteve » Wed Jul 07, 2004 11:40 am

i think speud can help with saving like he did with neocd
Check out the beats of rage community at http://borrevolution.vg-network.com/
speud
DCEmu Uncool Newbie
DCEmu Uncool Newbie
Posts: 1459
Joined: Sat Dec 27, 2003 10:40 pm
Has liked: 0
Been liked: 0
Contact:

Post by speud » Wed Jul 07, 2004 12:04 pm

in neocd saving was already implemented in the original emulator, so converting it to VM saving in the DC port was quite easy. id like to work on saving later though, but im a bit too busy atm. anyway, that will require more time and work than implementing it in neocd, so be patient.
http://blueswirl.fr.st - DC Online Tools and Downloads

thx to Wack0 for the avatar ;)
User avatar
Stef.D
DCEmu Respected
DCEmu Respected
Posts: 114
Joined: Wed Oct 15, 2003 1:46 am
Has liked: 0
Been liked: 0
Contact:

Post by Stef.D » Thu Jul 08, 2004 2:06 am

Rev. Layle wrote:how much memory mapped i/o and interrupts does the z80 in the genesis have to deal with?
Z80 ram, and all 68000 area via a 32kb bank access.
also have direct access to VDP, PSG and YM2612...

I still not started anything about Z80, didn't got any free time yet :-/
Rev. Layle
Insane DCEmu
Insane DCEmu
Posts: 190
Joined: Sun Jun 27, 2004 8:35 pm
Location: stillwater, ok
Has liked: 0
Been liked: 0
Contact:

Post by Rev. Layle » Thu Jul 08, 2004 8:42 am

ok, so is VDP, PSG, YM2612 accessed through ports or memory mapped i/o (or some other way)? luckily bank switching is not too hard to emulate
BlackAura
DC Developer
DC Developer
Posts: 9951
Joined: Sun Dec 30, 2001 9:02 am
Has liked: 0
Been liked: 0

Post by BlackAura » Thu Jul 08, 2004 9:29 am

Anything that's connected directly to the Z80 (the PSG and YM2612, I think) should be accessed through ports (Z80-based machines usually use ports). Anything that's connected to the 68k's address space (the PSG and YM2612 again, the VDP) uses memory mapped I/O (because the 68k doesn't have any ports).
Rev. Layle
Insane DCEmu
Insane DCEmu
Posts: 190
Joined: Sun Jun 27, 2004 8:35 pm
Location: stillwater, ok
Has liked: 0
Been liked: 0
Contact:

Post by Rev. Layle » Thu Jul 08, 2004 9:47 am

hmm, at least (well, to me, because i am no emulation expert) that port programming would be easier to emulate. with memory mapped i/o, you have to detect on EVERY memory write weather the write is going an i/o device or just regular memory (or even trying to write to a ROM portion which is read only)
User avatar
Stef.D
DCEmu Respected
DCEmu Respected
Posts: 114
Joined: Wed Oct 15, 2003 1:46 am
Has liked: 0
Been liked: 0
Contact:

Post by Stef.D » Thu Jul 08, 2004 9:57 am

Unfortunatly nothing is connected to the Z80 IO ports on genesis :-/
All IO stuff (PSG, YM2612, VDP, bank register...) are directly mapped to memory if this was your question... so yeah, on memory writes and reads we have to test them.

< 0x4000 = RAM
0x60XX = bank register
0x70XX = IO ports (VDP, PSG, YM2612)
>= 0x8000 = banked area

But it's still a very simple memory map, test for ram first, then banked area and io port last...
Rev. Layle
Insane DCEmu
Insane DCEmu
Posts: 190
Joined: Sun Jun 27, 2004 8:35 pm
Location: stillwater, ok
Has liked: 0
Been liked: 0
Contact:

Post by Rev. Layle » Thu Jul 08, 2004 10:14 am

well poo - luckily you know which portion of memory has the memory mapped i/o - so you only have to test the first byte - then maybe have a second switch to test the second byte

something like

Code: Select all

// nAddr is unsigned int with memory address

unsigned int char nFirstByte = nAddr >> 8;
unsigned int nSecondByte = nAddr & 255;

switch (nFirstByte)
{
   case 0x60:
      switch (nSecondByte)
      {
         // do bank register stuff
      }
      break;
   case 0x70:
      switch (nSecondByte)
      {
         // i/o stuff here
      }
      break;
   default:
      if (nFirstByte <= 0x40)
         // RAM
      else
         // banked area
}
but i guess you have something like that already - maybe more optimized

edit: just read your post again, i guess you would want to test for RAM and banked area first becuase they are going to be hit the most. and (againe dit) come to think of it: a few "if"s may do the trick better and faster than the stupid shifts, ands, and swtiches i used.

is there anything in the 0x50XX range of memory?
Last edited by Rev. Layle on Thu Jul 08, 2004 10:34 am, edited 4 times in total.
Post Reply