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

ZiCog a Zilog Z80 emulator in 1 Cog

1282931333441

Comments

  • heaterheater Posts: 3,370
    edited 2010-03-06 18:01
    Just got the experiment a LMM version of ZiCog running CP/M again.
    It's running as a full up Z80 even if all most of the old ops done in overlay are now broken.
    IN, OUT and DAA work as well as they ever did though.

    There are 37 free LONGs in COG on this TriBlade version !

    Now I have to repair some old overlaid code as it uses self-modifying code which will not work as LMM.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    For me, the past is not over yet.
  • pullmollpullmoll Posts: 817
    edited 2010-03-06 19:52
    heater said...
    Now I have to repair some old overlaid code as it uses self-modifying code which will not work as LMM.

    Good to hear that you're making progress!

    I don't quite understand why self modifying code is impossible. Once the code is loaded in cog RAM, it can modify itself!? You "only" need to patch in the addresses... Ah, I'm beginning to understand your problem.

    Juergen

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    He died at the console of hunger and thirst.
    Next day he was buried. Face down, nine edge first.
  • heaterheater Posts: 3,370
    edited 2010-03-06 20:06
    As you probably see, something like:
                            movs    :get_reg, vector
                            nop
    :get_reg                rdbyte  data_8, vector                
    
    



    Works fine as an overlay but not when executed a LONG at a time as LMM.

    I manage to get LDIR working so now the Z80 exercise test runs again and shows all current failures.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    For me, the past is not over yet.
  • pullmollpullmoll Posts: 817
    edited 2010-03-06 20:44
    heater said...
    As you probably see, something like:
                            movs    :get_reg, vector
                            nop
    :get_reg                rdbyte  data_8, vector                
    
    



    Works fine as an overlay but not when executed a LONG at a time as LMM.

    I manage to get LDIR working so now the Z80 exercise test runs again and shows all current failures.

    Ok, now I got it. I was misinterpreting LMM as you just pulling the code from an external RAM into cog, not as executing the ZiCog code itself with the LMM technique.

    I'm a little stuck and will opt out for today. I heard that a cold beer is waiting for me in the pub smile.gif

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    He died at the console of hunger and thirst.
    Next day he was buried. Face down, nine edge first.
  • heaterheater Posts: 3,370
    edited 2010-03-06 21:22
    This is not a release of ZiCog.

    Attached is my experimental ZiCog using LMM instead of overlays. In case anyone wants to see what goes on and/or has some suggestions. This only runs on TriBlade.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    For me, the past is not over yet.
  • Bill HenningBill Henning Posts: 6,445
    edited 2010-03-06 21:25
    Nice work heater!
    heater said...
    This is not a release of ZiCog.

    Attached is my experimental ZiCog using LMM instead of overlays. In case anyone wants to see what goes on and/or has some suggestions. This only runs on TriBlade.
    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    www.mikronauts.com E-mail: mikronauts _at_ gmail _dot_ com 5.0" VGA LCD in stock!
    Morpheus dual Prop SBC w/ 512KB kit $119.95, Mem+2MB memory/IO kit $89.95, both kits $189.95 SerPlug $9.95
    Propteus and Proteus for Propeller prototyping 6.250MHz custom Crystals run Propellers at 100MHz
    Las - Large model assembler Largos - upcoming nano operating system
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2010-03-06 23:52
    The zicog works 24/7!

    And it looks like I missed a few things while it was nightime here. Maybe I'll just have to give up sleep?

    Can you explain what the LMM is? For DAA the old code was
    'daa overlay. This is a "load/execute" overlay.
                            org     OVERLAY_START
    daa_ovl
                            rdbyte  data_8, a_reg
                            mov     nibble, data_8             'Isolate low nibble of accumulator
                            and     nibble, #$0F                        
                            cmp     nibble, #10 wc             'Test for greater than 9                
                            test    flags, #aux_bit wz            'Test auxillary carry
                if_nz_or_nc add     data_8, #$06               'Add 6 to accumulator if greater than 9 or AUX carry
                            add     nibble, #6                 'Check for AUX carry from low nibble
                            test    nibble, #%00010000 wz
                            muxnz   flags, #aux_bit            'and set AUX flag if so.      
                            mov     nibble, data_8             'Isolate high nibble of accumulator
                            shr     nibble, #4
                            cmp     nibble, #10 wc             'Test for greater than 9
                            test    flags, #carry_bit wz       'Test carry flag
                if_nz_or_nc add     data_8, #$60               'Add (6 << 4) to accumulator if greater than 9 or carry
                            test    data_8, #$100 wz           'Check for 8 bit carry out
                if_nz       or      flags, #carry_bit          'Set carry flag if so (N.B. Do NOT clear carry if not so)
                            and     data_8, #$FF wz, wc
                            muxz    flags, #zero_bit           'Set Z80 zero flag from props zero
                            muxnc   flags, #parity_bit
                            test    data_8, #128 wz
                            muxnz   flags, #sign_bit
                            wrbyte  data_8, a_reg                        
                            jmp     #fetch
    nibble                  long    0
                            long    $0[noparse][[/noparse]($ - OVERLAY_START) // 2]    'fill to even number of longs (REQUIRED)
    daa_ovl_end
                            fit    $1F0
    
    



    and the new code is

    'DAA LMM.
    daa_lmm                 rdbyte  data_8, a_reg
                            mov     nibble, data_8             'Isolate low nibble of accumulator
                            and     nibble, #$0F                        
                            cmp     nibble, #10 wc             'Test for greater than 9                
                            test    flags, #aux_bit wz            'Test auxillary carry
                if_nz_or_nc add     data_8, #$06               'Add 6 to accumulator if greater than 9 or AUX carry
                            add     nibble, #6                 'Check for AUX carry from low nibble
                            test    nibble, #%00010000 wz
                            muxnz   flags, #aux_bit            'and set AUX flag if so.      
                            mov     nibble, data_8             'Isolate high nibble of accumulator
                            shr     nibble, #4
                            cmp     nibble, #10 wc             'Test for greater than 9
                            test    flags, #carry_bit wz       'Test carry flag
                if_nz_or_nc add     data_8, #$60               'Add (6 << 4) to accumulator if greater than 9 or carry
                            test    data_8, #$100 wz           'Check for 8 bit carry out
                if_nz       or      flags, #carry_bit          'Set carry flag if so (N.B. Do NOT clear carry if not so)
                            and     data_8, #$FF wz, wc
                            muxz    flags, #zero_bit           'Set Z80 zero flag from props zero
                            muxnc   flags, #parity_bit
                            test    data_8, #128 wz
                            muxnz   flags, #sign_bit
                            wrbyte  data_8, a_reg                        
                            jmp     #fetch
    
    



    No ORG at the beginning. So is this some sort of 'portable' code that you can read in from elsewhere?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    www.smarthome.viviti.com/propeller
  • heaterheater Posts: 3,370
    edited 2010-03-07 06:21
    Dr_A:

    Firstly overlays and LMM solve the same problem: How to run PASM programs that are bigger than 496 LONGs on a single COG. They both do it by fetching code from somewhere outside the COG, putting it in the COG and the jumping to it to execute it.

    Overlays are done by fetching a whole sequence of LONGs in one go, a complete subroutine say, and then jumping to the start of that sequence when it is in COG somewhere.

    LMM does it by loading only one PASM instruction at a time. Executing that. Then looping around and fetching the next instruction.

    Both techniques could be used to run extra code from HUB, or external RAM or SD card or wherever. ZiCog is only interested in executing extra code from HUB. We are already executing Z80 ops from external RAM and that is slow enough.

    They both have their tricks to get the speed up. In the overlay loader the code sequences are actually read in backwards, from to to bottom, because you can hit the HUB access "sweet spot" that way. It's also cleverly arranged that the last instruction loaded, which is actually the first instruction in the sequence, overwrites the last instruction of the loader loop so that execution naturally flows out of the loader loop into the overlay sequence with out any loop count checking or jumps.

    LMM gets its speed from the nature of the load execute loop especially if it is unrolled a few times. Have a look in that code for "lmm_fetch". You can make LMM run faster by having the instructions loaded in reverse but that gets a bit confusing to program. It did work in PropAltair though.

    For the original classic post on the invention of LMM by Bill Hennning se here http://forums.parallax.com/showthread.php?p=615022

    For ZiCog LMM may be a bit slower but it has the advantage that you don't need an overlay area in your COG, well it's only one LONG. Also the LMM execute loop can be smaller than the overlay loader routine. This frees up space for all the other stuff we need.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    For me, the past is not over yet.
  • heaterheater Posts: 3,370
    edited 2010-03-07 12:22
    Pullmoll: Just put your LONG saving suggestions in. Very good.

    Sadly the suggested DAA does not work not in the CP/M SURVEY program or in the exerciser test. Attached is the DAA as I used it. Notice the JMPs have been changed to LMM jumps.

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

    Post Edited (heater) : 3/7/2010 12:27:53 PM GMT
  • heaterheater Posts: 3,370
    edited 2010-03-07 14:48
    Pullmoll: I just notice that you have made the mistake every new user of the Prop. makes. There should be # marks in front of your jump labels :das and :flags.

    Not that it matters because I changed the jumps to LMM style but that got me thinking so I had another look.
    Hmm... there's a lot of $'s in front of what looks like they should be decimal not hexadecimal numbers. And a $ missing where I'm sure hexadecimal is meant.

    I have fixed up all that and was about to test again. Bahh! the rechargeable battery on my Prop is down. The only supply I have.

    Edit: Scratch much of the above, I guess the $ WERE supposed to be there !!!

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

    Post Edited (heater) : 3/7/2010 3:37:28 PM GMT
  • pullmollpullmoll Posts: 817
    edited 2010-03-07 18:31
    heater said...
    Pullmoll: I just notice that you have made the mistake every new user of the Prop. makes. There should be # marks in front of your jump labels :das and :flags.

    Not that it matters because I changed the jumps to LMM style but that got me thinking so I had another look.
    Hmm... there's a lot of $'s in front of what looks like they should be decimal not hexadecimal numbers. And a $ missing where I'm sure hexadecimal is meant.

    I have fixed up all that and was about to test again. Bahh! the rechargeable battery on my Prop is down. The only supply I have.

    Edit: Scratch much of the above, I guess the $ WERE supposed to be there !!!

    Uh..oh..my head smile.gif I was sure that this code couldn't be bug free. Anyway, it looks like you got it right now. Great!
    I'll need some time and some coffee to recover before I delve into Prop again.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    He died at the console of hunger and thirst.
    Next day he was buried. Face down, nine edge first.
  • heaterheater Posts: 3,370
    edited 2010-03-07 18:44
    Pullmoll: Actually no I can't get it to work.

    Then I started having a hard look at the MAME C version. I made the observation that both arms of the if...else...are identical except one side adds adjustments to "a" and the other side subtracts the same adjustments.

    This made me think we could create a simpler version by setting up the adjustments first according to the N flag, +/-0x06 and +/-0x60. Then we can we don't need the if... anymore and can run through the rest of the code without any jumps.

    Like so:

    {
      // MAME Version.
       UINT8 a = (Z)->A;
        if ((Z)->F & NF) {
            if (((Z)->F&HF) | (((Z)->A&0xf)>9)) a-=6;
            if (((Z)->F&CF) | ((Z)->A>0x99)) a-=0x60;
        }
        else {
            if (((Z)->F&HF) | (((Z)->A&0xf)>9)) a+=6;
            if (((Z)->F&CF) | ((Z)->A>0x99)) a+=0x60;
        }
        (Z)->F = ((Z)->F&(CF|NF)) | ((Z)->A>0x99) | (((Z)->A^a)&HF) | SZP[noparse][[/noparse]a];
        (Z)->A = a;
    }
                            rdbyte    A, a_reg    'Fetch the A register
                mov    a, A        'Take a working copy
                            mov    nibble, A    'Get low 4 bits of A register
                and    nibble, #$0F
    
                            mov    adj_60, #$60    'Set up adjustment values
                            mov    adj_06, #$06
    
                            test    flags, #neg_bit wz 'Negate adjustments if neg flag set
                      if_nz    neg    adj_60, adj_60
            if_nz    neg    adj_06, adj_06
    
                            'If half carry or low nibble > 9 adjust by +/- 0x06
                            test    flags, #aux_bit wz
                cmp    nibble, #$0A wc
           if_nc_or_nz    add    a, adj_06
    
                            'If carry or A reg greater than 0x99 adjust by +/- 0x60
                            test    flags, #carry_bit wz
                cmp    A, #$9A wc
           if_nc_or_nz    add    a, adj_60
    
                            'Clear all flags except carry and neg
                andn    flags, #(carry_bit | neg_bit)
    
                            'Set carry if A reg greater than 0x99
                    cmp    A, #$9A wc
                  if_nc    or    flags, #carry_bit
    
                            'Set half carry of bit 4 changed
                xor    A, a
                and    A, #aux_bit
                or    flags, A
    
                            'Set Sign Zero and Parity
                            and     a, #$FF wz, wc
                            muxz    flags, #zero_bit           'Set Z80 zero flag from Props zero
                            muxnc   flags, #parity_bit
                            test    data_8, #$80 wz
                            muxnz   flags, #sign_bit
    
                            wrbyte  a, a_reg                   'Write the result to the A rgeister
                            jmp     #fetch
    
    



    I introduced some extra longs for adj_06, adj_60, a, and A just to make it more readable, we can get rid of those later.

    Needless to say it does not work either.

    Help!!!

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    For me, the past is not over yet.
  • pullmollpullmoll Posts: 817
    edited 2010-03-07 20:07
    heater said...
    Help!!!

    Well, that code should work fine. You're right, it's just the ADDs/SUBs that are different.
    Hmm... Is it true that the Prop's CMP clears the carry if the value is greater or equal to the source? I think so, but I'm not entirely sure. Also, to mimic the OR in the C code, I did the cmp nibble,#$09+1 and cmp nibble #$99+1 only if Z was not set. But this was wrong, because you can't test for NC then.

    Is the if_nc_or_nz correct? nz means zero flag clear, but you want to test aux_bit and carry_bit set.

    So your code looks right to me and I don't know why it shouldn't work. Perhaps it's time to fire up a Prop simulator and step through the code?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    He died at the console of hunger and thirst.
    Next day he was buried. Face down, nine edge first.

    Post Edited (pullmoll) : 3/7/2010 8:22:04 PM GMT
  • heaterheater Posts: 3,370
    edited 2010-03-07 20:42
    I should use "and" to clear all the flags not "andn".
    Can't see what else is wrong.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    For me, the past is not over yet.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2010-03-07 22:58
    Re heater
    >Firstly overlays and LMM solve the same problem: How to run PASM programs that are bigger than 496 LONGs on a single COG. They both do it by fetching code from somewhere outside the COG, putting it in the COG and the jumping to it to execute it.


    I'm starting to understand this now. Especially after the explanation about how the overlays (that appear to be in the middle of the zicog code) are in fact at the end of the zicog code. Ok, maybe this is a question for Brad but lets assume you have some spin code and it happens to almost fill up the propeller code space. Then you decide to put in some cog code. The compiler compiles that just fine. Now lets add an overlay. The overlay runs over the cog space but the compiler does not complain about that - it just keeps on compiling into opcodes. Now lets add another overlay. It just so happens that the entire code now is too big to fit in hub ram.

    Will the compiler keep on compiling, even though the code now does not fit in hub ram?

    And could you set up a compiler so that it did keep on compiling, even though that program could never fit in a propeller, but it still gives you a useful complete program that might be 100k in length?

    The reason I ask that is that if you have such a 100k program, all the internal variables within that program are all correct. So any reference to a memory location will still work. Now, obviously a bit of code that now ends up bigger than a propeller memory can't reference an internal memory location that is outside the propeller memory. But it can reference variables earlier on in the program.

    Such a 100k binary file could then be very useful. You take the bottom 32k and put it into propeller ram. And the rest you put into a file on an sd card and then you read that into external ram. Now, any bit of code that you might bring into a cog has all the variables correct - eg you might have the Z80 registers sitting at a certain point in hub ram and any external cog code can reference those variables.

    I'm thinking that creating such a program could be very simple - just have a check box in a compiler that if checked, the compiler does not stop compiling at 32k. Maybe it gives a warning but it still keeps compiling. Then you might need an external program that processes the binary file and produces the bits of cog code as seperate files ready to go into the sd card.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    www.smarthome.viviti.com/propeller
  • BradCBradC Posts: 2,601
    edited 2010-03-08 00:09
    I know homespun has the ability to compile large programs (Catalina uses it), but I don't know how it handles spin and multiple objects. The spin code is always after the DAT segment in the object, and the interpreter does not really have the ability to cope with spin > $7FFF (rom gets in the way). Jazzed is the one to ask on this as he's been working on a "bigspin" kinda thing on and off for a little bit. I guess mpark could give you a quick 10 second on how homespun manages bigger than 32k, but I *suspect* it's only really assembling one big DAT section (for LMM code). I don't know this however.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    You only ever need two tools in life. If it moves and it shouldn't use Duct Tape. If it does not move and it should use WD40.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2010-03-08 06:30
    Ok, I'm digesting that. The problem is there never seems to be enough memory, and the frustrating thing is that the board I have has 448k of free memory. But I don't seem to be able to use that any more than I can use the 14k of leftover space in the propeller that was used to load up cogs with data. Heater (thanks!) gave me a few longs with the hint that the IX IY instructions were not used and so no point in having them and with the precious 20 or so longs I managed to code up some really amazing wireless network code that truly does have peer to peer networking. Cool things can be done with tiny amounts of code! But I'm now running short again.

    I'm pondering opening up a seperate bank of ram and putting Z80 code in that and running it alongside CP/M - with OUT instructions to flip between banks.

    But there is this other idea of allowing assembly code to 'overflow' the 32k limit. Maybe it is too hard in spin - I gather spin is interpreted but I'm not sure of the detail of how it passes values eg with a call/gosub. So I'm not sure what would be allowed for code that is out of range. Fine if you only reference values in range, but simple things like the internal value(s) of a subroutine - where does that live?

    So maybe lets add a simple rule that the only overflow code is pasm code. I guess somehow the object that overflows has to be the last one in the list (does the compiler add the objects alphabetically or in some other way?), and then the last code has to be pasm code that overflows in the same way that cog code overflows into hub?

    Maybe it is not possible, in which case bank switching might be the way to go. I need to get my head around that as MP/M can do this but it had a common top 16k and the lower 48 got changed, but with the way the hardware works I think the entire 64k gets switched in and out. Unless you put some sort of extra code in the zicog to detect which bank - and guess what there is no room in the zicog cog! So the switching might have to be done with an OUT instruction and it flips banks, stores the PC, changes the PC to 0, runs code at location 0 (which has to be put there somehow) stores all the registers, runs some code, restores the registers, restores the PC and goes back to the original bank. Hmm - that is going to use up some spin code too! Or - do that as pseudo z80 op code and pull in an overlay and do it in pasm. Boy is this complicated!

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    www.smarthome.viviti.com/propeller
  • heaterheater Posts: 3,370
    edited 2010-03-08 07:20
    Dr_A: Seems like what you want is a) Have a nice CP/M system running b) Have some other big program running that can run from external memory as well.

    I don't recommend that the "other" external memory system be Z80. After all it is limited to 64K at the moment and is slow. No, what you want is ICC or Catalina or Zog (soon) that can run huge programs from external RAM. Perhaps there are other solutions I'm not aware of.

    Problem then is sharing access to external RAM from two simultaneously executing systems.Here we need help from Bill's VMCog to manage the memory access. This is not a trivial problem, kind of requires an OS to manage it or at least something that acts like a HUB but for the ext RAM.

    As for CP/M bank switching, ZiCog already includes code for bank switching. It swaps the low 48K of Z80 RAM around in many banks whilst the to 16K is "resident". Same as AltairZ80 simulator. This only takes a handful of longs and does not need any support from Spin. We don't worry about how code/data gets into those other banks as ultimately it is up to CP/M 3 or MP/M and the programs they run to manage it, just like on a real bank switched CP/M machine.

    Have a look at the ZiCog memory read/write byte functions to see how it is done. It has never been tested [noparse]:)[/noparse]

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    For me, the past is not over yet.
  • heaterheater Posts: 3,370
    edited 2010-03-08 07:39
    PullMoll:

    >> Is it true that the Prop's CMP clears the carry if the value is greater or equal to the source?

    C is set if dest is less than source. Else C is cleared. It's the same a SUB but with NR.

    Could you tell me if the A register in MAME is signed or unsigned?

    I mean PASM has CMP and CMPS perhaps we have the wrong one. I tried CMPS for compares against A but still no luck.

    Do I really have all the flag bits in the right positions?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    For me, the past is not over yet.
  • pullmollpullmoll Posts: 817
    edited 2010-03-08 08:17
    heater said...
    PullMoll:

    >> Is it true that the Prop's CMP clears the carry if the value is greater or equal to the source?

    C is set if dest is less than source. Else C is cleared. It's the same a SUB but with NR.

    Could you tell me if the A register in MAME is signed or unsigned?

    I mean PASM has CMP and CMPS perhaps we have the wrong one. I tried CMPS for compares against A but still no luck.

    Do I really have all the flag bits in the right positions?

    Here's the MAME Z80 core definition of the flags. Your's look ok, too:
    #define CF 0x01
    #define NF 0x02
    #define PF 0x04
    #define VF PF
    #define XF 0x08
    #define HF 0x10
    #define YF 0x20
    #define ZF 0x40
    #define SF 0x80

    The A register is an unsigned char in MAME. It's actually part of a union to either access the A and F bytes or the AF word, which is an unsigned short.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    He died at the console of hunger and thirst.
    Next day he was buried. Face down, nine edge first.
  • heaterheater Posts: 3,370
    edited 2010-03-08 09:29
    OK so our unsigned comparisons are good.

    I just noticed that we compare A against $99 twice. Once to decide to add $60 or not and again to determine the carry flag. Room to save a long or two there. But that's not the problem.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    For me, the past is not over yet.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2010-03-08 09:47
    Re "As for CP/M bank switching, ZiCog already includes code for bank switching"

    I can't seem to find that. Am looking in the zicog version on page 1 of this thread. It has an ifdef mentioning banked memory but no associated code. Maybe I'm looking in the wrong spot. Cluso seems to have got it working?

    Though this is still complicated. What would you run in 'user 2' of banked memory? Another CP/M program, sure. But what I'm interested in is building up the spin layer underneath CP/M with more and more clever bits of code. And I'm not sure about one CP/M program in MP/M passing I/O which goes through another CP/M program in MP/M. Does that make sense?

    Probably not. Ok, what I want to do is flip a flag in CP/M such that instead of output going via a port or to the console, it goes via a smart program that packages up the bytes into packets, adds a header and a footer when the packet is full, and sends it on, and also sends on partially completed packets after a time delay. So - where do you put such a program? It might be only 10 lines of spin code but I have no space left for spin. Could it go via another MP/M program running under CP/M? Could it go via a small program written in Z80 sitting in another banked ram location? Or could it fit in a cunning overlay in pasm that is brought in from external ram for just the purpose?

    I need more space for spin. Ok, off to explore the binaries of spin code to see how the interpreter works and whether it can be fudged in some way to run code that is imported into the spare memory left when a cog is filled...

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    www.smarthome.viviti.com/propeller
  • pullmollpullmoll Posts: 817
    edited 2010-03-08 09:48
    heater said...
    OK so our unsigned comparisons are good.

    I just noticed that we compare A against $99 twice. Once to decide to add $60 or not and again to determine the carry flag. Room to save a long or two there. But that's not the problem.

    If this DAA still fails the test, then perhaps the N flag isn't set right by some instructions, or destroyed when it should be preserved. Do you set it on the 16 bit SBC HL,r16 and clear it on ADC HL,r16?
    There are also weird flag effects of the INI, OUTI, IND, OUTD opcodes and their repeated versions. They all set sign and zero flag as you would expect, but they also set the neg_bit from bit #7 of the value read or written to the I/O port. Further they set aux_bit and carry_bit if (L + value) & 0x100!

    CPL and NEG instructions always sets the neg_bit, as do SUB, SBC, CP and DEC.

    Edit: Also, do you have the aux_bit set by the BIT opcodes? It's always set to 1 when executing them. When bit #7 is tested, the sign flag will also be set if bit #7 is set, and when the tested bit is not set, the zero flag and the parity flag are both set to 1.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    He died at the console of hunger and thirst.
    Next day he was buried. Face down, nine edge first.

    Post Edited (pullmoll) : 3/8/2010 10:03:12 AM GMT
  • heaterheater Posts: 3,370
    edited 2010-03-08 10:12
    Good questions re: flags. I already thought about that a bit and did some experiments:

    1) Comment out the test for neg from DAA such that it always adds the adjustments. Then run the CP/M SURVEY program.
    SURVEY uses DAA to print memory usage and such in HEX. It prints correct results using ZiCogs old DAA. It prints gibberish using this modified MAME version. I think the modified new one should work here just like the old DAA.

    2) Run the instruction set exerciser EXZ80DOC. This tests instructions by setting up thousands of test cases of various operands, memory and flag values. It builds a check sum of results which it compares with running the same tests on a MOSTEK Z80. In this way it can test DAA on it's own even if the other ops are not setting flags correctly.
    It fails [noparse]:([/noparse]

    In general I cannot be sure yet that all ops set all flags correctly. Especially N. The exerciser EXZ80DOC will pick up all wrong documented flags though so we know were things need fixing.

    I think I'm going to proceed like this.
    1) Build a test C harness program for the DAA routine that tests all possible values of A, C, H, N and prints the results.
    2) Build a PASM/Spin test harness for the PASM DAA which does the same. We can capture the output from the BST terminal.
    3) Compare.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    For me, the past is not over yet.
  • pullmollpullmoll Posts: 817
    edited 2010-03-08 10:41
    heater said...

    I think I'm going to proceed like this.
    1) Build a test C harness program for the DAA routine that tests all possible values of A, C, H, N and prints the results.
    2) Build a PASM/Spin test harness for the PASM DAA which does the same. We can capture the output from the BST terminal.
    3) Compare.

    That's the way to go. That way you can be sure that DAA is correct and 'just' some other opcode doing wrong things with the flags.

    There's a channel #propeller on freenode and I'll linger in there.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    He died at the console of hunger and thirst.
    Next day he was buried. Face down, nine edge first.

    Post Edited (pullmoll) : 3/8/2010 11:47:04 AM GMT
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2010-03-08 10:42
    Sorry heater I'm asking you to multitask two problems here!!

    With the ability to load files off an sd card, space for spin code is more precious than space for data. I put in a little sniffer line to see what the dpb was being used, and it seems to be drive type 0 "dpb_0 '8MByte Default SIMH Altair HDSK params"
    which I suspect is by design rather than accident that the first one is the hard drive parameters rather than listing floppy drives first. The Dracblade is only ever going to use 8mb hard drive images so I commented out all the other drive parameters and it all seems to work ok.

    Also - in the ruthless quest for space - all text for error messages shortened to Er1, Er2 etc.

    And commented out the spin code to peek and poke to all 512k ram from within CP/M. I might be using the ram for MP/M instead!

    And out goes the code for constat and punstat (just ignores these)

    120 longs gone, and I did have some free, and F8 says I have 273 longs free.

    Now there is some space to put in some useful networking code.

    I'm now eyeing off the Font table in the vga object. Hmm - how can I load this in after loading code into the cog?

    Addit - a comment for Juergen - if you use the CNT in spin and take the last 8 bits, you could use that as the R register. Useful for random number generation.

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

    Post Edited (Dr_Acula) : 3/8/2010 10:49:33 AM GMT
  • pullmollpullmoll Posts: 817
    edited 2010-03-08 11:18
    Dr_Acula said...
    Addit - a comment for Juergen - if you use the CNT in spin and take the last 8 bits, you could use that as the R register. Useful for random number generation.

    Uh, no, not really [noparse]:)[/noparse] If anything I'm going to count R as the Z80 would do, i.e. once per instruction. But I fear that all the emulation code and tables will overflow the hub RAM soon and then my try is over.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    He died at the console of hunger and thirst.
    Next day he was buried. Face down, nine edge first.
  • heaterheater Posts: 3,370
    edited 2010-03-08 11:46
    Dr_A: I removed floppy support from ZiCog a long time ago. Those parameters are for drives using the hard disk driver code in the CBIOS. Even if they do describe floppy format disks. I believe the last parameter blocks were for 1M floppy and 512K RAM disk or such. If you only have one hard disk you only need one parameter block. Or change it so that all the drives use the same parameter block.

    Shortening messages is a great idea. You could go wild though and have a text file on SD full of messages that get's read into the space where ZiCog PASM lives after ZiCog is started.

    No idea about the font tables, never looked in there.

    Ah, Pullmoll is into cycle accurate emulations, we have no truck with such things, it would slow us down.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    For me, the past is not over yet.
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2010-03-08 12:01
    Pullmoll is going to build the most perfect Z80 emulation the world has ever seen *grin*

    Ok, heater, I should not have spoken too soon. And now I don't understand the code. I tried to go to drive B and it crashed.

    But I am very confused between drive numbers (0 to 7) which equals drives A-H, and the drive parameter tables.
    PRI out_hdskport_param
    'Handle writes to the hdskport when get params command is in progress
      case hdsk_command_pos
        1:
          hdsk_drive := io_data
          hdsk_command_pos++
          hdsk_reply_pos := 0
          hdsk_dpb_ptr := @hdsk_dpb + (hdsk_drive * 19)     'Point to correct DPB for this drive
          vgatext.dec(hdsk_drive)
    
    



    Now that last line is a little debug line and as you select drive A, B, C it changes from 0,1,2 etc.

    But hdsk_dpb is a data block defined at the beginning of the program with different data types for each drive.

    Or Is It??

    I just checked it again. We have
    dpb_7 '440K RAM disk as HDSK params
    dpb_6 '1MByte Altair mits2 floppy as HDSK params (no skew)

    and there do seem to be subtle differences between each drive type.

    But from the code above, if I select drive H, am I not selecting the dpb_7? And if so, why is it working when this has different parameters to other drive types (drive H for me is an 8mb simh drive the same as all the others).

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    www.smarthome.viviti.com/propeller
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2010-03-08 12:11
    No scratch that, I found the bug. Drives A-F are all simh in my code, and drives G and H are other formats. I never got round to testing G and H. Ha, there is a bug on my part. So now have commented out all but the first dpb and the modified code is thus
    PRI out_hdskport_param
    'Handle writes to the hdskport when get params command is in progress
      case hdsk_command_pos
        1:
          hdsk_drive := io_data
          hdsk_command_pos++
          hdsk_reply_pos := 0
          'hdsk_dpb_ptr := @hdsk_dpb + (hdsk_drive * 19)     'Point to correct DPB for this drive
          hdsk_dpb_ptr := @hdsk_dpb ' always point to dpb 0 for the dracblade
          'vgatext.dec(hdsk_drive) ' so can see drive number 0-7
          hdsk_last_command := hdsk_current_command         'OUT's for current command completed
          hdsk_current_command := hdskNull
        other:
          PrintStringCR(string("Er10"))
          repeat
    
    



    This saves lots of longs. I can't see any need for other disk formats for the moment.

    And I have had a brainwave re networking which I can't quite articulate yet, but I think it involves sending batch files from one board to the next, running the batch file which in turn sends a different (shorter) batch file to the next board and so on. So can send data to and from remote boards via multiple hops. Why is this exciting? Well, I think it means you need no special code in the spin layer to handle outputting data in data packets. All data is 'raw', but only two boards are ever talking at once as the batch files move through the network.

    So... this means I truly do have a lot of free memory. And when Juergen gets the dracblade he can start adding overlays without having to worry about running out of hub ram.

    Life is good!

    addit re Juergen "There's a channel #propeller on freenode and I'll linger in there."

    can you pls give some more details about that. I downloaded mIRC and tried searching for a propeller channel but no luck. Any suggestions re client and/or channel?

    scratch that - found this propeller.wikispaces.com/Join+us+on+IRC!

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

    Post Edited (Dr_Acula) : 3/8/2010 12:27:13 PM GMT
Sign In or Register to comment.