Shop OBEX P1 Docs P2 Docs Learn Events
ZiCog a Zilog Z80 emulator in 1 Cog - Page 23 — Parallax Forums

ZiCog a Zilog Z80 emulator in 1 Cog

1202123252641

Comments

  • Dr_AculaDr_Acula Posts: 5,484
    edited 2009-12-08 10:48
    Ah, ok. There do seem to be a few instructions missing. I thought I might start with something simple - EX AF,AF'

    Re you problems, I've got no room in the cog, but heaps of room in the hub for more overlays. Possibly something now in the cog could go into an overlay to free up cog space. Not sure if I need cog space yet, but...

    first question, where are the alternate registers stored?

    In the main program I see this:
    register_file word
    bc_reg        word      0
    de_reg        word      0
    hl_reg        word      0
    af_reg        word      0
    bc_reg_alt    word      0 
    de_reg_alt    word      0
    hl_reg_alt    word      0
    af_reg_alt    word      0
    im_reg        word      0
    ix_reg        word      0
    iy_reg        word      0
    sp_reg        word      0
    pc_reg        word      0  
    
    



    but so the alt registers are there. But I couldn't find the equivalent in the cog?

    I see this

      reg_base := LONG[noparse][[/noparse]cpu_params]
      c_reg    := reg_base + 0
      b_reg    := reg_base + 1
      e_reg    := reg_base + 2
      d_reg    := reg_base + 3
      l_reg    := reg_base + 4
      h_reg    := reg_base + 5
      f_reg    := reg_base + 6
      a_reg    := reg_base + 7
      im_reg   := reg_base + 8
      ix_reg   := reg_base + 18
      iy_reg   := reg_base + 20
      sp_reg   := reg_base + 22
      pc_reg   := reg_base + 24     
    
    



    are they in the gap from 8 to 18?

    Hmm - more fundamental questions. In the spin code of the zicog there is this

      'The following code sets up the Overlay Load Parameters
      daa_ovl_     := OverlayParams(@daa_ovl,     @daa_ovl_end)
    #ifdef CPU_Z80
      ldi_ovl_     := OverlayParams(@ldi_ovl,     @ldi_ovl_end)
      cpi_ovl_     := OverlayParams(@cpi_ovl,     @cpi_ovl_end)
      ini_ovl_     := OverlayParams(@ini_ovl,     @ini_ovl_end) 
    
    



    So - if you add one more instruction to that list, does that take more bytes out of the cog, or out of the overlay (and hence not out of the cog)?

    Or was this the point you got stuck with 3) in your list?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    www.smarthome.viviti.com/propeller
  • heaterheater Posts: 3,370
    edited 2009-12-08 11:40
    OK, EX and EXX is a good place to start if you are so inclined.

    As you see the alternate register set is already defined. af_reg_alt and friends. And in the COG there are the HUB addresses of the registers "a_reg" and friends.

    As you rightly point out there is no "a_reg_alt" in the COG. This is deliberate. The idea is that when EX is executed rather than shuffle the contents of the reg and its alternate around we just change the value of the HUB pointer, a_reg, in the COG to point to the other version of the reg. From then on the alternate register is used instead of the original. So to switch to the alternative A reg just add 8 to the "a_reg" pointer in the COG. To switch back subtract 8 again.

    Of course this requires keeping track which version of the register you are pointing at so that you know to add or subtract on the next EX.

    Or does it?. Instead of adding / subracting 8 why not just XOR the "a_reg" pointer in COG with %1000 every time EX is encountered. It quickly switches the pointer to the "other" reg either way around with no need to keep track of which one is actually in use at any moment.

    Hmmm.. This XOR trick probably requires that the bc, de, hl, af regs are located in HUB memory such that bit 3 of their HUB address is 0. Then XOR'in bit 3 of the pointers with 1 will do the add/subtract correctly.

    How to get that memory alignment is an exercise for the reader...


    Re: Overlays. The overlay mechanism requires their to be a table of addresses of the overlay code block addresses in HUB RAM. This used to be in COG. I moved that table out to HUB RAM to save COG space. Look for "overlay_table" in zicog.spin. So it should be that adding overlays does not consume any COG space[noparse]:)[/noparse]

    N.B. As long as none of the new overlays is bigger than the largest one that exists already (DAA)

    Hope this all makes sense.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    For me, the past is not over yet.
  • Cluso99Cluso99 Posts: 18,069
    edited 2009-12-08 15:00
    I am following this as I will need the updated ZiCog for the RamBlade release [noparse]:)[/noparse]

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Links to other interesting threads:

    · Home of the MultiBladeProps: TriBlade,·RamBlade,·SixBlade, website
    · Single Board Computer:·3 Propeller ICs·and a·TriBladeProp board (ZiCog Z80 Emulator)
    · Prop Tools under Development or Completed (Index)
    · Emulators: CPUs Z80 etc; Micros Altair etc;· Terminals·VT100 etc; (Index) ZiCog (Z80) , MoCog (6809)
    · Search the Propeller forums·(uses advanced Google search)
    My cruising website is: ·www.bluemagic.biz·· MultiBladeProp is: www.bluemagic.biz/cluso.htm
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2009-12-08 22:51
    I got a message back from the author of BBC basic and he says he used lots of Z80 instructions. Even the R register as a random number generator (something I did myself a few months in Sbasic too). So we may have our work cut out for us getting Z80 instructions working. In the meantime, I guess the Zicog might have to be renamed an 8080cog??

    heater has given me the building blocks to have a go at one instruction. >=DAA in space should be possible. Overlay table in hub is fantastic news. So - just a matter of grabbing values and manipulating them. I'm still not 100% sure of where the values are but some detective work should settle that. For EXX I was thinking of declaring a single temp variable, then BC to temp, BC' to BC then temp to BC'. Repeat for the others.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    www.smarthome.viviti.com/propeller
  • heaterheater Posts: 3,370
    edited 2009-12-09 00:15
    Dr_A,

    It's great you are in touch with Mr Russel. The R register indeed. We can to that I guess, with even better randomness.

    The 8080 version of ZiCog already has a name "iCog". That way if Zilog or Intel don't sue me for trademark infringement the Apple can[noparse]:)[/noparse]

    However iCog will need working over to get the flags right for 8080 and pass EX8080.COM tests.

    As for getting register "rdbyte somewhere, a_reg" will get you the A reg to "somewhere" in COG and "wrbyte somewhere, a_reg" will put it back.

    You should not need another temp variable, there is data_8 and data_16 already for use as scratch pad.

    Did your read my post re how to do the EX and EXX register swapping without the brute force reading of register, swapping through a temp and writing out again.

    It is only necessary to add 8 to a_reg to make it point to the alternate A register in HUB. Subtract 8 to get it back again. Just have to remember which register set you are in so you know if to add or subtract 8. Same for the other regs.

    Now that we have space in HUB (what with dropping support for the demo version soon) for more overlays we can just keep throwing overlays at it until it works [noparse]:)[/noparse]

    I'm hoping I have time to look at these missing ops at the weekend.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    For me, the past is not over yet.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2009-12-09 02:12
    Thanks heater. I'll quote Mr Russell's reply (my comments have > in front as he was quoting them)

    I'm afraid that I tended to squeeze every last drop of performance out
    of my Z80 code, so BBC BASIC is probably more fussy than most programs
    in requiring the instructions to work exactly as they are supposed
    to. Incidentally a common trap that people fall into is to emulate LD
    A,R as LD A,0 on the basis that nobody can possibly be using the R
    (refresh) register in their code. BBC BASIC does - to seed the random
    number generator!

    > BBC Basic could also be a useful stepping stone to getting a 6502
    > emulation working on the propeller using the same board.

    The well-defined and documented interface between the 'language' and
    the 'OS' on the BBC Micro makes it much easier to port 6502 BBC BASIC
    to another platform than would otherwise be the case.

    > The updated documentation is very much appreciated.

    Thank you. If you spot any errors or serious omissions let me know.


    Well, now we know which instructions to work on...

    Thanks for the heads up re data_8 and data_16 being temp variables. I have left them alone as I tried using them as temp variables in the memory read write code and it crashed. But looking back, what was probably happening is something else was using them too, then calling the memory read write! So... good to know they are there.

    re your cunning xor stuff in hub, I must confess I have no idea how that would work. My solution (slower is it is) is the only one I can get my head around. I don't even understand how you can write some pasm code and run out of cog space but then call some pasm code an overlay and list it right underneath the first lot of code and suddenly it doesn't run out of space. I know it resides in hub somehow instead of the cog but I don't understand exactly how. I'm sure your code will be much more cunning, use less space and be faster. I also don't understand the variables very well - which is the 'real' value of a register, the hub variable or the cog one?

    So heater, your expertise is very much needed here with the 'Grand BBC Basic' project!

    I was thinking of sending you a board but this all works on the triblade too, and the triblade has free hub memory as well. Are you still on the demo board or do you have a triblade working?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    www.smarthome.viviti.com/propeller
  • Cluso99Cluso99 Posts: 18,069
    edited 2009-12-09 03:38
    Drac & heater:
    Do not rename ZiCog. The extra instructions can come with time. Just need a caveat that not everything is emulated yet.

    Now for the R trick for a random seed - just read the cnt in it's place and and the required bits.

    The overlay method and simple code is described in my overlay loader (see utilities link in my signature to find it). I really should post it to the obex.

    Not sure if you have been following, but I have 1-pin video running and 1-pin keyboard concept is close to proving.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Links to other interesting threads:

    · Home of the MultiBladeProps: TriBlade,·RamBlade,·SixBlade, website
    · Single Board Computer:·3 Propeller ICs·and a·TriBladeProp board (ZiCog Z80 Emulator)
    · Prop Tools under Development or Completed (Index)
    · Emulators: CPUs Z80 etc; Micros Altair etc;· Terminals·VT100 etc; (Index) ZiCog (Z80) , MoCog (6809)
    · Search the Propeller forums·(uses advanced Google search)
    My cruising website is: ·www.bluemagic.biz·· MultiBladeProp is: www.bluemagic.biz/cluso.htm
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2009-12-09 07:52
    Hi Heater,

    I think I'm going to need a lot of help with the extra instructions. In fact, it may be beyond me without starting afresh or ending up asking you a question every 10 seconds.

    For instance, I am looking at EX AF, AF'

    Apart from the fact I don't understand your cunning tricks in hub, I figured this should be simple. First, get AF. I figured - what else uses AF as a single unit? I know, PUSH AF.

    So first bit of code is to look up the opcode for PUSH AF which is F5 then scan down the table and it gives this bit of code:
    {F5}                    long    get_af             + (push_               << 9)                           '*PUSH AF
    
    



    I went up the beginning to the spin code and found this
      reg_base := LONG[noparse][[/noparse]cpu_params]
      c_reg    := reg_base + 0
      b_reg    := reg_base + 1
      e_reg    := reg_base + 2
      d_reg    := reg_base + 3
      l_reg    := reg_base + 4
      h_reg    := reg_base + 5
      f_reg    := reg_base + 6
      a_reg    := reg_base + 7
      im_reg   := reg_base + 8
      ix_reg   := reg_base + 18
      iy_reg   := reg_base + 20
      sp_reg   := reg_base + 22
      pc_reg   := reg_base + 24
    
    



    So, I figure, the a register is stored in a_reg and the f register (flags) is stored in f_reg because these are listed one after the other.

    So, ok the code for getting the combo of af would be a fetch to the a_reg register then one to the f_reg register.

    Indeed, there is a little routine called get_af that starts off thus:
    get_af                  rdbyte  data_16, a_reg
                            shl     data_16, #8
    
    



    So - I figure, the next line would be to rdbyte on the f_reg and OR this with data_16. Except that it isn't. The next line is
                            or      data_16, flags
                            jmp     #vect_2    
    
    



    So, there is a variable 'flags' somewhere, and presumably somewhere in the first bit of code for an instruction it is getting f_reg and putting it into 'flags'. Or maybe f_reg isn't used any more.

    This is where me coding could be a problem because I know enough to be dangerous. I'd have dropped in a rdbyte on the f_reg and I'll be it would have worked most of the time, except I'd have been using the wrong flag parameter and sooner or later there would have been someones code that would have set the flags, called an EX AF, AF' and my code would have changed the flags.

    What do you suggest?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    www.smarthome.viviti.com/propeller
  • heaterheater Posts: 3,370
    edited 2009-12-09 08:32
    DR_A.

    Yes, be careful, data_8 and data_16 are used in memory read/right. It's just that mostly they can be used because they end up holding the thing you want to write anyway. The idea originally was that they are used as a kind of ALU operand register.

    Re: running out of space.

    Basically anything you put between the first "org 0" and "fit $1F0" is "resident" COG code and eats valuable COG space.

    Anything you put in an overlay sits in HUB RAM until pulled in by the overlay loader. So as long as you clone and overlay, say by making a copy of daa_ovl then changing it's name and content you can keep adding overlays with out eating COG space. Be sure to add entries to the overlay tables and add to the overlay initialization part in Spin at the top.

    One restriction:

    There has to be space in the COG where overlay code sections are swapped in and out. This has to be as big as the biggest overlay, daa_ovl in our case. So you will find that adding to daa_ovl or making another one bigger than daa_ovl starts to eat COG space again as it requires a larger area in COG to be loaded into.

    Re the variables:

    The main things are the registers of course. They are defined as 16 bit regs in zicog_cpm.spin "bc_reg", "de_reg" etc. They are defined in a specific order for easy access here and there so don't mess with that. In the PASM there are pointers (HUB addresses) set up to point to the 8 bit registers in that collection. "a_reg", "b_reg" etc. Such that "rdbyte data_8, a_reg" does what you expect it to. Where "data_8" is a normal LONG in the COG and "a_reg" is a long in COG holding the HUB address of the A reg.

    The trick with EX, perhaps you can it see now, is that if you change the "a_reg" such that it points to a different place in HUB (i.e. contains the HUB address of the alt A reg) then all the rest of the code that uses a_reg will now be using the alternate a_reg value.

    Turns out that to point to the alt A reg you only need to add 8 to the pointer "a_reg". Subtract 8 to get back to the original.

    This could be done by inverting a bit 3 in a_reg IF the reg file was position correctly in HUB. But that is an optimization for later.


    Re Boards:

    My original home made demo board is now history. It's Propeller and one other are firmly welded into a TriBlade board as blades #1 and 2# running at 104MHz !

    I'd love a DracBlade though....

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    For me, the past is not over yet.
  • heaterheater Posts: 3,370
    edited 2009-12-09 09:07
    DR_A: You are right to be confused with that AF stuff....

    Here is the general plan:

    1) Most registers are living in HUB space. They must be accesses with rdbyte/word and wrbyte/word during every instruction emulation that uses them. There are reasons for this, lost in time. Originally regs were in COG but emulator versions with them in HUB ended up being smaller/faster. No need for AND with FF for example to keep them in range of a byte. Makes it easy/fast to access them as byte or in pairs as words. You can see this in the get_??/put_?? routines.

    2) BUT Regs that are used in nearly all instructions, or quite often anyway, are kept in the COG for speed reasons. That is the program counter in "pc", the stack pointer in "sp" and the flags in "flags". These do not need to be fetched for every opcode.

    3) These COG based regs (pc, flags, sp) MUST be loaded from the HUB register file on start up. They must also be written back to HUB during a "break" so that he register dump display is correct. See "break_ovl". You should not have to worry about this loading and unloading, just use "pc", "flags" and "sp".

    Now it's good to have more than one brain looking at this and it's good to ask questions. I'm sure we will spot some errors or optimizations this way. I must admit I've been staring at that code and have re-written it so many times I'm going "PASM blind". You end up reading what you want the code to do rather than what it actually does[noparse]:)[/noparse]

    The nice thing is that if you add new ops as overlays then you can only create a bug in your new op. Unlikely to break the existing stuff. You cannot be so "dangerous"[noparse]:)[/noparse]
    Then we have EXZ80DOC as a regression test.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    For me, the past is not over yet.
  • heaterheater Posts: 3,370
    edited 2009-12-09 09:11
    Cluso: Using CNT as the R register is sweet.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    For me, the past is not over yet.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2009-12-09 23:21
    Mr Russell says there are 35 instances of EX AF,AF' in BBC Basic so I guess this is a 'high priority' instruction?

    R register using CNT would be perfect - great idea.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    www.smarthome.viviti.com/propeller
  • Cluso99Cluso99 Posts: 18,069
    edited 2009-12-12 06:43
    I am trying to think of a way to time code on·ZiCog/CPM. Why? I want to time the improvement from TriBlade to RamBlade, and I am sure Drac would like to be able to time his DracBlade as well.

    I am thinking aloud... Maybe I can trap screen/terminal writes and if a "CR" is written, insert (write)·the "CNT" value·before the newline. There will be a subtle error in this method because the spin hex function differs depending on the value supplied to it.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Links to other interesting threads:

    · Home of the MultiBladeProps: TriBlade,·RamBlade,·SixBlade, website
    · Single Board Computer:·3 Propeller ICs·and a·TriBladeProp board (ZiCog Z80 Emulator)
    · Prop Tools under Development or Completed (Index)
    · Emulators: CPUs Z80 etc; Micros Altair etc;· Terminals·VT100 etc; (Index) ZiCog (Z80) , MoCog (6809)
    · Search the Propeller forums·(uses advanced Google search)
    My cruising website is: ·www.bluemagic.biz·· MultiBladeProp is: www.bluemagic.biz/cluso.htm
  • Toby SeckshundToby Seckshund Posts: 2,027
    edited 2009-12-12 09:12
    I haven't had a chance to even think about the extention/completion to the instuction set for the last couple of days, but the explainations that are coming now hold many more clues as to how it was done, than I latched onto before.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Style and grace : Nil point
  • heaterheater Posts: 3,370
    edited 2009-12-12 11:15
    Toby and all, I was hoping to have some time to work on this over this week end. Well I have the time but I'm in the wrong place. So best I can do is look over anything that comes up.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    For me, the past is not over yet.
  • Cluso99Cluso99 Posts: 18,069
    edited 2009-12-12 12:12
    heater: I have been following, but my time has been spent elsewhere.

    My thoughts are that the unused/uncoded opcodes need to cause a dump of the instruction. Then, as time permits, and as instructions required to work are discovered, they can be implemented. You original 8080 goal has been achieved and then you added some Z80 instructions as it was decided that most of the Z80 instructions were not used by the majority of programs (not all).

    Currently, we have a great solution in ZiCog. It can be compiled as 8080 or Z80. If it fails under Z80, 8080 can be run, and the error reported. A great many programs run on CPM with the current ZiCog Z80 implementation. With the new bootloader, both binaries will be on the SD file system, so either can be run.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Links to other interesting threads:

    · Home of the MultiBladeProps: TriBlade,·RamBlade,·SixBlade, website
    · Single Board Computer:·3 Propeller ICs·and a·TriBladeProp board (ZiCog Z80 Emulator)
    · Prop Tools under Development or Completed (Index)
    · Emulators: CPUs Z80 etc; Micros Altair etc;· Terminals·VT100 etc; (Index) ZiCog (Z80) , MoCog (6809)
    · Search the Propeller forums·(uses advanced Google search)
    My cruising website is: ·www.bluemagic.biz·· MultiBladeProp is: www.bluemagic.biz/cluso.htm
  • heaterheater Posts: 3,370
    edited 2009-12-12 13:25
    Yep, first thing we need is for all unimplemented op's to break the emulation and dump the regs. I already put that first on the "how to attack this" list many posts back.

    "then you added some Z80 instruction"

    "some", "some". We are 90% of the way through the EXDOCZ80 test, that's a big "some" [noparse]:)[/noparse]

    We are actually much closer to a full Z80 than you may think. It's the lack of COG and the HUB space that set the limit on what we could do.

    Now with dropping support for the demo board version we have HUB space for overlays and a good chance of getting this completed.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    For me, the past is not over yet.
  • Cluso99Cluso99 Posts: 18,069
    edited 2009-12-12 13:39
    WOW - I didn't think it was that close to done. I haven't looked, just recall you saying you were only adding those that were required, but that was so long ago now.

    I looked at ZiCog last night at the instruction fetch section. I can integrate the new RamBlade fetch directly into the fetch code with no extra instructions. RamBlade already reduces a read from 7 to 4 instructions. With this, we will save another 4 instruction executions (call/ret, mov address,pc and add pc,#1) as the inc can be done directly in the read delay and work on the pc directly. Possibly other places as well. This should speedup the emulation some more smile.gif

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Links to other interesting threads:

    · Home of the MultiBladeProps: TriBlade,·RamBlade,·SixBlade, website
    · Single Board Computer:·3 Propeller ICs·and a·TriBladeProp board (ZiCog Z80 Emulator)
    · Prop Tools under Development or Completed (Index)
    · Emulators: CPUs Z80 etc; Micros Altair etc;· Terminals·VT100 etc; (Index) ZiCog (Z80) , MoCog (6809)
    · Search the Propeller forums·(uses advanced Google search)
    My cruising website is: ·www.bluemagic.biz·· MultiBladeProp is: www.bluemagic.biz/cluso.htm
  • heaterheater Posts: 3,370
    edited 2009-12-12 14:05
    Yep. I did say I would add just enough Z80 stuff to get CP/M to use LDIR etc in it's BIOS.

    But then with your overlay loader I got on a roll. Something like two thirds of ZiCog.spin is now Z80 ops !

    Inlining the instruction fetch from RAM sounds just perfect.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    For me, the past is not over yet.
  • Ron SutcliffeRon Sutcliffe Posts: 420
    edited 2009-12-13 05:04
    @heater, Clusso.

    No sure if this is the best thread to post this query anyway I'm back to Zilog after doing other things, in my other life J

    Yesterday I spent a day getting nowhere L

    My SD card does not share pins with xmem so I have replaced tbp2 obj with·my hxd driver, and have started from scratch.

    Putting the hxd driver into its own cog is always going to be very slow, but for now it should allow me to get Zilog running.

    ( I can fit it in if I use 8080 only )

    The hxd cog uses four longs cmd, adr, datin and retval. The driver polls cmd waiting for a R or W and then executes, returning a value in retval.

    (in the case of a read)

    The set up works fine, but fails when called from the cpu cog. Gets stuck in a loop SP counts dowm from $ffff to 57d4 then hangs.

    Any thoughts ???

    Ron



  • Cluso99Cluso99 Posts: 18,069
    edited 2009-12-13 07:36
    Looks like the cpu is not fetching the instructions from sram.
    Have you also modified the read_memory_byte and write_memory_byte sections in ZiCog?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Links to other interesting threads:

    · Home of the MultiBladeProps: TriBlade,·RamBlade,·SixBlade, website
    · Single Board Computer:·3 Propeller ICs·and a·TriBladeProp board (ZiCog Z80 Emulator)
    · Prop Tools under Development or Completed (Index)
    · Emulators: CPUs Z80 etc; Micros Altair etc;· Terminals·VT100 etc; (Index) ZiCog (Z80) , MoCog (6809)
    · Search the Propeller forums·(uses advanced Google search)
    My cruising website is: ·www.bluemagic.biz·· MultiBladeProp is: www.bluemagic.biz/cluso.htm
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2009-12-13 09:55
    @heater, I'm going to move the thread on the extra Z80 instructions over from the Dracblade to here as I think it is more relevant here.

    Ok, the aim here is to add all the instructions needed to run BBCBasic. These include those that use the alt registers, AF' and BC' DE' and HL'

    The space for these is already reserved in the 'main' program in hub
    DAT
    
    'The Z80 Registers.
    'Do not change the order of these.
    'Registers are defined in pairs as words so as to enable them to be
    'accessed individually as BYTE or in pairs as WORD.
    'The ordering makes it easier to find a register specified by a 3-bit
    'register field within an op code or to swap between main and
    'alternate register sets. 
    register_file word
    bc_reg        word      0
    de_reg        word      0
    hl_reg        word      0
    af_reg        word      0
    bc_reg_alt    word      0 
    de_reg_alt    word      0
    hl_reg_alt    word      0
    af_reg_alt    word      0
    im_reg        word      0
    ix_reg        word      0
    iy_reg        word      0
    sp_reg        word      0
    pc_reg        word      0 
    
    



    Now, lets move over to the zicog. The location of im_reg has been fixed (though it doesn't matter as interrupt modes are not used)
    This is what I think is needed:
    PUB start(cpu_params) : okay | reg_base, io_base
    '' Start CPU simulator - starts a cog
    '' returns false if no cog available
    ''
    ''   cpu_par_params is a pointer to CPU parameter list
                                                                                               
      stop
    
      reg_base     := LONG[noparse][[/noparse]cpu_params]
      c_reg        := reg_base + 0
      b_reg        := reg_base + 1
      e_reg        := reg_base + 2
      d_reg        := reg_base + 3
      l_reg        := reg_base + 4
      h_reg        := reg_base + 5
      f_reg        := reg_base + 6
      a_reg        := reg_base + 7
    '  bc_reg_alt   := reg_base  + 8
    '  de_reg_alt   := reg_base  + 10
    '  hl_reg_alt   := reg_base  + 12
    '  af_reg_alt   := reg_base  + 14
      im_reg       := reg_base + 16
      ix_reg       := reg_base + 18
      iy_reg       := reg_base + 20
      sp_reg       := reg_base + 22
      pc_reg       := reg_base + 24
    
    



    with the four commented out lines not working yet.

    Now, let's uncomment the first one and try compiling. It comes back with 'error - unresolved symbol bc_reg_alt

    So - let's go about half way down zicog and here is the code and the 4 lines added that I'd like:
    'Pointers to Z80 registers in HUB RAM
    b_reg                   long    0
    c_reg                   long    0
    d_reg                   long    0
    e_reg                   long    0
    h_reg                   long    0
    l_reg                   long    0
    m_reg                   'Note: m_reg is an alias for f_reg
    f_reg                   long    0
    a_reg                   long    0
    'bc_reg_alt    word      0
    'de_reg_alt    word      0
    'hl_reg_alt    word      0
    'af_reg_alt    word      0
    im_reg                  long    0
    ix_reg                  long    0
    iy_reg                  long    0
    sp_reg                  long    0
    pc_reg                  long    0 
    
    



    Now, the problem is that I can't add any of those 4 variables as it runs out of memory.

    So, some questions:
    1) Are all these variables needed?
    2) Why are these variables longs when at most they store word variables?

    For example, the long ix_reg only appears in one line in the zicog:
    z80_DD                  mov     xy_reg, ix_reg             'Point XY reg to IX reg for DD prefix ops
                            mov     dispatch_tab_addr, dispatch_tab_dd_addr  'Z80, DD Prefix
                            jmp     #dispatch   
    
    



    I'm still not entirely sure how that works, eg ix_reg is sitting in hub ram and I can't quite see how it gets into the cog in order to be moved to xy_reg. But regardless, the point here is that ix_reg is not a variable that is used much. Indeed, given it is hardly used at all, maybe it isn't needed as a variable and it could be done in another way and that way could lead to a solution for freeing up the longs needed to access the alternate register words in hub?

    Eg, we know the location of regbase. So, could you put that in a temp variable, add an integer (eg 14 to get the alt af regiser), then read the word at that location and put that into xy_reg. That code is in an overlay so doesn't matter about the space.

    iy_reg could be treated the same, so could im_reg and maybe we could even free up 3 longs?

    Speed is not the issue here as the alt register instructions are not needed very often. And in any case, the slowest thing about an instruction like ex af,af' would be loading the overlay itself, right?

    I still don't quite understand the overlays and the zicog, but in general terms, there are some values sitting in hub ram that represent the registers. The opcode loads an overlay and we can write some code in that overlay as long as it is less than DAA in size. Could we point to the register, not with a named long, but rather with some code that reads the regbase, adds a constant n, and then gets the byte (or word) value from hub ram, manipulates it, and puts it back with the same regbase+n.

    Is there an even simpler way - can you call regbase+n a constant known to the compiler (but not needed in the pasm code), that you can use to get the value at location n in hub?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    www.smarthome.viviti.com/propeller
  • heaterheater Posts: 3,370
    edited 2009-12-13 10:15
    Dr_A: "Why are these variables longs when at most they store word variables?"

    In the zicog.spin those variable like "b_reg" are NOT variables holding WORDS.

    They are LONGS that contain the HUB addresses of the byte registers in HUB as defined in zicog_cpm.spin.
    This way you can access the registers in HUB with "rdbyte data_8, b_reg" and "wrbyte data_8, c_reg".
    You can aslo use rd/wrword for the register pairs.

    Now one could say that HUB addresses can only be 15 bits (for 32K) so why use 32 bit longs to hold them?

    Well, rdbyte, wrbyte etc need to use a LONG as the target HUB address.

    BUT if we were very sneaky we could put other WORD variables into the high halves of those LONGS. When the LONG is used as a HUB address by rd/wrbyte the top half (where our variable is hiding) would be ignored.

    This would make the code even more unreadable but would potentially save 18 words, 9 LONGS.


    Edit: Forget the above. Putting vars in the high halves of HUB pointers would require shifting etc to access them eating more LONGS that we save.

    Anyway as I said before you don't need any of those _alt register pointers. Just add and subtract from the existing pointers to switch the whole emulation from using one set of regs to another. It can all be done in an overlay with no "resident" code.

    I'll have a look at the rest of your post later.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    For me, the past is not over yet.

    Post Edited (heater) : 12/13/2009 10:27:11 AM GMT
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2009-12-13 10:35
    I don't quite understand the alt pointer trick yet - and was figuring that by working out how this works for one instruction I might be able to code some more instructions.

    ok, the variables like b_reg pointing to locations in hub rather than containing values themselves makes a lot of sense. I added a comment to remind myself of this:
      reg_base     := LONG[noparse][[/noparse]cpu_params]      ' memory locations in hub that contain these variables
    
    



    Next, given im_reg isn't used anywhere I deleted it. And saved a long.

    So - given there isn't room to put in the af registers, any reason I can't do something like this (syntax not right I know)

    mov tempvariable,reg_base
    add tempvariable,14
    get value in the new tempvariable location
    manipulate that value
    put it back into tempvariable

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    www.smarthome.viviti.com/propeller
  • heaterheater Posts: 3,370
    edited 2009-12-13 10:58
    Why would you want to do that? The only variables you want to access in HUB already have LONGS in COG set up as pointers to those variables (that is the registers: b_reg, c_reg etc and the I/O control block: io_command etc)

    What I am saying is this:
    1) On start up the a_reg in COG is set up to "point to" the a_reg in HUB (defined in Spin)
    2) You can read the A register from HUB with "rdbyte data_8, a_reg"
    3) You can read the flags register from HUB with "rdbyte flags, f_reg"
    4) You can write these with wrbyte also.

    Now, when you want to do EX all you have to do is add 8 to the a_reg and f_reg LONGS in COG.
    From then on as the emulation continues every access to A and F will be to the alternate set.
    On the next EX you just subtract 8 from those same pointers and we are back working with the original A and F registers.
    Only thing is you need to remember somewhere when you have done an EX so that you know to subtract 8 next time instead of adding 8 again.
    The other "only thing" is that in normal running the flags register is kept in COG as "flags". For speed reasons. So you have to be sure to write out "flags" prior to doing the pointer add/sub. And then read them back afterwards. This will keep "f_reg" in HUB in sync with "flags" in HUB.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    For me, the past is not over yet.
  • Toby SeckshundToby Seckshund Posts: 2,027
    edited 2009-12-13 11:14
    We need a "Z80 emulation on the Parallax Propeller, for dummies" writeup, PLEASE smilewinkgrin.gif

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Style and grace : Nil point
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2009-12-13 11:37
    Yes, a writeup would help!!

    I'm still confused. Just to check - all register values are stored in Hub ram. Not locally in the COG? Except for the flag register. But only the flag register.

    So I presume somewhere is a bit of generic code that puts the flag into hub and brings it back from hub?

    I don't understand the EX AF, AF' solution. Ok, add 8 to the AF pointer and it now points to AF'. But don't you also need a variable to say you did that? And another variable to say you did it to EXX. I'm out of variables in the cog.

    Also, it makes the printout of the registers messy in spin as you have to read off those variables in spin code to know how to print out the registers. So that implies the variable storing the switch has to be in hub, not cog, so it is correctly passed when it is single stepping or crashes. So if the variable is stored in hub, you need a pointer to it and that pointer needs to be accessible in the cog. Another register if you like. And There is still the problem of being out of longs in the cog.

    A simple solution risks getting very complicated. It also risks escaping from the zicog code into the underlying main program that does things like print out the registers, so you need to declare a new variable (or two) in the main program in the triblade, dracblade, tobyblade main and rewrite the spin code that displays the registers.

    I'm trying to think of a way to keep this just inside the zicog. Speed is not important here. Though I think it ought to come out pretty fast anyway. EX AF, AF' invoves moving the value in AF to a temp variable, AF' to AF and temp variable to AF'.

    All the things involving storing and restoring the flag would be common to any code you have to write.

    Addit: Just found this in the text at the top
    'v0.5 - 18 Mar 2009  - Moved A reg and flags back into HUB. A couple of percent slower but saves 15 or so LONGs.
    '                      Many fixes to get alu ops, logic ops, double adds and neg passing in EXZ80DOC tests.
    '                      Moved NEG function (alu_neg) into overlay to save LONGs.
    
    



    So on the 10th March did the A and flags get moved to cog, on the 18th they got moved back to hub and sometime later than that the flags only got moved back to the cog?

    AdditAddit

    Found the bit of code that passes flags back to hub on a break:
    break_ovl               wrword  pc, pc_reg
                            wrbyte  flags, f_reg
                            wrword  sp, sp_reg                         
                            mov     data_8, #io_cmd_break      'Set I/O command to BREAK
    
    



    So I presume the command to update the hub flag is wrbyte flags,f_reg

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    www.smarthome.viviti.com/propeller

    Post Edited (Dr_Acula) : 12/13/2009 12:04:38 PM GMT
  • Toby SeckshundToby Seckshund Posts: 2,027
    edited 2009-12-13 12:04
    Hey, don't go naming my version. It's just a simplified rip of yours. Nothing clever going on here - move along.

    I think that at the expence of speed a vector out of cog into hub (and spin?) will be the only way to clear a working area ( I have no idea if that statement is kak ). That or revert to Heaters multiple Cogs, at the expence of some of Dr_A's periferals. I do not use the LCD, so there must be a cog going begging there.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Style and grace : Nil point
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2009-12-13 12:29
    But the TobyBlade is cool, it shows you can make these Zicog things at home!

    The name was heater's idea - this snippet was posted on the 'open source' thread two hours before mine. So it is now 'official' *grin*

    heater - This is already an issue with ZiCog's simple use of #ifdef. If I were to put it in OBEX should I just put the Z80 emulator version or the 8080 version. Should it be the HUB RAM version or the external RAM version. If external RAM should it be for the TriBlade or RamBlade or DracBlade or Toby/Blade or Hydra, or Morpheous.

    Ok, starting to build up a new instruction. It goes in an overlay underneath alu_set_ovl and before the #endif

    (That is the #endif that is at the end of a list of Z80 overlays. Below the #endif is the break overlay that is common to Z80 and 8080

    This seems to be the common minimum code for an overlay:
    '---------------------------------------------------------------------------------------------------------
    
    '---------------------------------------------------------------------------------------------------------
    'ex af,af' overlay.  rdbyte and wrbyte are value,address for both
                            org     OVERLAY_START
    ex_af_af
    
    
    
                            jmp     #fetch
                            long    $0[noparse][[/noparse]($ - OVERLAY_START) // 2]    'fill to even number of longs (REQUIRED)
    ex_af_af_end
                            fit     $1F0
    
    
    



    I'll flesh out the code later. Next thing is to check that calling it does not take any extra memory. BRB

    ok, in the PUB start put in the new overlay
      alu_set_ovl_ := OverlayParams(@alu_set_ovl, @alu_set_ovl_end)
      ex_af_af_    := OverlayParams(@ex_af_af, @ex_af_af_end)               ' new ex af,af' command
    #endif
      break_ovl_   := OverlayParams(@break_ovl,   @break_ovl_end) 
    
    



    Then about two thirds of the way down the zicog there is a CON with the overlay numbers. Add our new overlay
    alu_res_ovl_no = $18
    alu_set_ovl_no = $19
    ex_af_af_no    = $1A  
    
    



    right under that is a DAT. I'm not 100% sure why this doesn't crash the compile as adding this long ought to, but it doesn't as yet...

    {18}alu_res_ovl_        long    0-0                        '||
    {19}alu_set_ovl_        long    0-0                        '||
    {1A}ex_af_af_           long    0-0  
    
    
    



    Next I need to work out how to get from the instruction list to the overlay. Heater has an unfinished jump for EXX that jumps to a location EXX in the main cog code (but with no code there), and I suppose you could jump to a location then load the overlay, but I think there is a smarter way where it jumps to an overlay directly from the list of op code numbers. I just need to decode that...

    Ok, getting close, I think it might be something like
                       long    vector_overlay     + (ex_af_af_no         << 9)
    
    



    and I'm not 100% sure but I think it fits in the last line of this code fragment, as 08 is the opcode for ex af,af'
    dispatch_table_00
    {00}                    long    fetch                                                                     'NOP
    {01}                    long    get_immediate_word + (put_bc              << 9)                           'LXI  B  *
    {02}                    long    get_a              + (put_memory_bc       << 9)                           'STAX B  *
    {03}                    long    get_bc             + (increment_word      << 9) + (put_bc          << 18) 'INX  B  *
    {04}                    long    get_b              + (increment_byte      << 9) + (put_b           << 18) 'INR  B  *
    {05}                    long    get_b              + (decrement_byte      << 9) + (put_b           << 18) 'DCR  B  *
    {06}                    long    get_immediate_byte + (put_b               << 9)                           'MVI  B  *
    {07}                    long    get_a              + (alu_rlc             << 9) + (put_a           << 18) 'RLC     *
    {08}                    long    not_implemented 
    
    



    I could have made a mistake in the above. For instance I'm not sure how it distinguishes between opcodes that happen to have one byte instructions (like ex af,af') and ones that have several bytes. So I hope I copied the right examples.

    Next thing is to flesh out the actual code, and I can do that by testing it each step. First might be to see if I can put a value in A and put in a break and get it to print that value when I execute EX AF,AF' in a tiny assembly program...

    And heater might be able to clarify this, but is there a convention that all overlay instructions end in 'ovl'?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    www.smarthome.viviti.com/propeller

    Post Edited (Dr_Acula) : 12/13/2009 1:15:23 PM GMT
  • heaterheater Posts: 3,370
    edited 2009-12-13 13:45
    Hey, I can't keep up with you guys[noparse]:)[/noparse] I'm supposed to be working on fee paying stuff today.

    "register values are stored in Hub ram" - YES

    "except flags" - YES and also SP. They are written out by the "break" overlay so that the Spin can see the changed values.

    "But don't you also need a variable to say you did that?" (EX thing) - YES.

    ". I'm out of variables in the cog" - YES [noparse]:)[/noparse] You either have to find a place in COG or keep it in HUB and do rd/wr on it every time.

    "And another variable to say you did it to EXX" - YES. See above.

    "Also, it makes the printout of the registers messy in spin " NO it does not. Things like DDTZ do not show you the "shadow" registers. I propose that Spin just prints all of them so that you can see what is going on.

    "So on the 10th March did the A and flags get moved to cog, on the 18th they got moved back to hub and sometime later than that the flags only got moved back to the cog?" - PROBABLY this thing was changing all the time as I was fighting to gain speed and or save space.

    "So I presume the command to update the hub flag is wrbyte flags,f_reg" YES as I said before.

    ", a writeup would help" - I'M SURE IT WOULD !![noparse]:)[/noparse] You guys are just the people to do it, hope you are taking notes and writing up as you go along [noparse]:)[/noparse][noparse]:)[/noparse]

    If this was easy it would be done already --- many more smilies [noparse]:)[/noparse][noparse]:)[/noparse][noparse]:)[/noparse]


    At risk of slowing down Z80 execution more than a bit one could move some ops into overlays:

    For example:

    set_carry
    complement_carry
    complement_byte

    would save you 9 LONGS already !

    "exchange" would save another 5 LONGS !

    P.S. I think the code at label "double_sub_hl_cy" needs looking at. It should at leas cause a break rather than just run into "exchange".

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    For me, the past is not over yet.
Sign In or Register to comment.