05 April 2018, 16:43 | #161 |
Registered User
Join Date: Dec 2014
Location: Netherlands
Posts: 1,406
|
Just out of curiosity, any progress?
|
09 April 2018, 23:17 | #162 | |
Out to Grass
Join Date: Jul 2010
Location: UK
Posts: 125
|
Quote:
Any luck with the clean up - or is it a total re-write ? |
|
26 April 2018, 15:48 | #163 |
Registered User
Join Date: Jan 2017
Location: London, UK
Posts: 433
|
Apollogies for the lack of updates, I have been back at work since March so haven't had any time to work on it.
The clean up became a rewrite, as I was previously running all my timing from the pixel generation, but really that's the wrong way around (and really my emulator worked more by luck than design) and I've restructured it to be based around the DMA slots, which is a bit more difficult to make work as you have to priority sequence the memory accesses. To make this work I need to understand this diagram... which isn't super clear |
11 May 2018, 13:10 | #164 |
Out to Grass
Join Date: Jul 2010
Location: UK
Posts: 125
|
Great to see you are still working on this,
i just wish i could help but its beyond my grey matter .. I just love how you guys get stuck into these projects, Good luck ! |
26 October 2018, 21:21 | #165 |
Ex nihilo nihil
Join Date: Oct 2017
Location: CH
Posts: 4,856
|
Hope you are going well and that you had some time to spend on the project
|
09 February 2019, 22:20 | #166 |
Registered User
Join Date: Jan 2017
Location: London, UK
Posts: 433
|
So, the project didn't die... I did a rewrite from scratch, with a proper DMA sequencer.
But for some reason it just wouldn't work, it would GURU during bootstrap. I tracked the problem down to the memory sub system, so I just dropped in the original system, and the Emulator would boot, but without display. I tracked the problem down to my DMA sequenced Copper. So again I dropped in the original code and it booted with display. The problem with the old code it was it was hacked together and is hardcoded to get Kick 1.2 to boot, it won't boot any other ROM. The problem I face at the moment is at some point (0xFC6CFC) an address of 0x0 is written to COP2LC, and then the copper (list @ 0x22F8) writes to COP2JMP... which causes the copper to write randomly to the Chipregs... Don't know why it's doing this Last edited by bloodline; 10 February 2019 at 00:10. |
10 February 2019, 00:08 | #167 |
Registered User
Join Date: Jan 2017
Location: London, UK
Posts: 433
|
So some more hacking around, it’s clear the Emulator is working (but without display), and my copper code seems to be running the copper list correctly... therefore I can only surmise that my beam counters are wrong.
It’s too late to try and think of some way to test my hypothesis tonight, but something about what I’m doing must be wrong. |
11 February 2019, 00:14 | #168 |
Registered User
Join Date: Jan 2017
Location: London, UK
Posts: 433
|
Reading through the HRM, I'm intrigued about the concept of "Long" lines and fields... I don't emulate this, not sure if that's going to cause problems...
here is a screenshot of the mess we have at the moment.... |
11 February 2019, 11:51 | #169 |
Registered User
Join Date: Jan 2017
Location: London, UK
Posts: 433
|
Theory time:
My DMA sequencer is a relatively simple affair. It's a just a function table, with each entry a function pointer to a DMA slot function. One function from the table is called every system cycle. The function called is whatever value is in the low byte of vhposr (i.e. the horizontal beam position). Every cycle the lower byte of vhposr is incremented, until it reaches 0xE3 (position 227), where it wraps back to 0 and increments the upper byte of vhposr by one (the vertical position), and the CIA B TOD counter is incremented. Internally I store the upper byte of vhposr with more than 8bits (with only the lower 8bits 0 to 7 visible when reading vhposr, and bit 8 visible as bit 0 of vposr)... This sounds complicated, but it really isn't*. When the upper byte (plus the extra bit of vposr) of vhposr reaches 0x106 (line 262 since I'm emulating a 200 line NTSC machine for now), The counter wraps back to 0, the CIA A TOD counter is incremented, and 0x8020 is written to the intreq register (to signal to the CPU a VBL as occurred). My internal copperPC is reloaded from Cop1Loc. This means the upper byte of vhposr, counts like this ...250, 251, 252, 253, 254, 255, 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, etc... weird I know, but this behaviour should be familiar to Amiga programmers. So all even entries (0,2,4,6 etc...) in the function table point to the same function. This function checks if the copper needs to use a memory cycle, if it does it calls the copper function and then returns, if the copper is currently waiting then the CPU is given the memory cycle. (I still use immediate blits so the blitter doesn't need the DMA at this time, blits happen as soon as the size register is filled). The copper is implemented as function which returns TRUE if the copper used the DMA slot memory cycle and FALSE if it didn't. quick psuedocodeish example: Code:
bool copperExecute(){ static int copperCycle = 0; static uint16_t IR1; static uint16_t IR2; switch(copperCycle){ case 0: IR1 = chipramW[copperPC>>1]; // here the chipram is a word array, thus the CopperPC needs to be divided by 2 IR1 = swap16(IR1); // big endian to little endian swap copperCycle = 1; copperPC +=2; return TRUE; The copper used this DMA slot so return true, and stop this slot being used by blitter or CPU. break; case 1: IR2 = chipramW[copperPC>>1]; IR2 = swap16(IR2); copperCycle = 2; copperPC +=2; return TRUE; The copper used this DMA slot so return true, and stop this slot being used by blitter or CPU. break; case 2: copperCycle = 4; //next copper execution cycle will default to the wait/skip instruction. //if bit 0 of IR1 = 0 then the next execution cycle will be the move instruction. if( (IR1 & 0x1)== 0){ copperCycle = 3 } return TRUE; // not sure if the copper should burn up a DMA slot? But I assume it does. break; case 3: chipramB[0xDFF000+IR1] = IR2 // write IR2 to the required chip register cycle = 0; // reset the coppercycle return TRUE; // use this DMA slot break; case 4: //Copper doesn't execute when b15 IR2 is clear and blitter is busy. if( (IR2 & 0x8000)==0 && (dmaconr & 0x4000) ==1){ return FALSE; } uint16_t compare = IR1 & 0xFFFE; //mask out the instruction bit uint16_t pos = vhposr & (IR2 & 0x7FFE); // mask out the evaluation bits. //is this a skip instruction? if( (IR2 & 0x1) ==1){ if( pos >= compare){ copperPC +=4; //Skip the next 4 bytes } copperCycle = 0; //reset the copperCycle and simply execute the next copper instruction. return FALSE //shouldn't need to burn up the DMA slot. } //The copper wll now just wait until the below condition is true before advancing to the next instruction. if(pos >= compare){ copperCycle =0; } return FALSE; // a wait instruction shouldn't burn up a DMA slot. break; } //We should never get here; Return FALSE: } All odd entries (1,3,5,7 etc...) in the function table point to a function to handle their specific DMA function (at the moment mostly just updating the bitplane registers and then when plane 1 dat is written, I dump out 16 chunky pixels to the host display buffer). The bitplane functions don’t start fetching until the vpos vhposr position is greater than the vpos value in the diwstrt register, and the hpos vhposr position is greater than the dffstrt value. I don’t currently use the hpos in the diwstrt register. *The vpos and hpos counters are actually 32bit, but these are only used internally. They are bitshfted and clipped to the relevant locations in the vposr and vhposr registers at the beginning of each DMA cycle. Only the vposr and vhposr registers are visible to the emulation. Last edited by bloodline; 11 February 2019 at 14:20. |
11 February 2019, 15:43 | #170 |
WinUAE developer
Join Date: Aug 2001
Location: Hämeenlinna/Finland
Age: 49
Posts: 26,502
|
- MOVE to chipramB: B=byte? It should be word.
- Copper MOVE does the move to custom register in second cycle (write goes directly to selected register, not to copper instruction register), there is no 3rd cycle in MOVEs. (Instruction is "decoded" when first word of MOVE is read) - SKIP does not actually skip anything but it isn't important normally. - When WAIT starts, it requires DMA slot. (3rd cycle). Also not important now. - CIA TOD counters don't increase exactly at the start of field/line but it also isn't important. - long/short fields can be ignored for now. - KS 1.x does few COPJMP2 writes before insert disk screen appears with COP2LC containing garbage. This usually won't cause problems (nothing is visible at this point anyway, just white screen) because if copper writes to "dangerous" register with COPCON=0: copper stops until next vblank. (Guess what happens if MOVE to "dangerous register" is "SKIP'd") - How do you detect writes to strobe registers like COPJMPx? - Almost all internal tests are equal comparisons (main exception is copper WAIT which is >=). For example if DDFSTRT==hpos: enable bitplane DMA for this scanline. More later, maybe.. |
11 February 2019, 16:24 | #171 | |||||
Registered User
Join Date: Jan 2017
Location: London, UK
Posts: 433
|
chipramB[] and chipramW[] are both arrays to the same memory pointer. One is 16 bit one is 8 bit:
uint8_t chipramB[524288]; uint16_t* chipramW = (uint16_t*)chipramB; A little hack so I can address the same memory as words or as bytes. Since the write to the register is byte addressed, I used the byte array. This hack works as long as addresses are word aligned... the code I wrote here is just psuedo code, to actually write a word to that address I would do: uint16_t* p = (uint16_t*)&chipramB[address]; *p = value; In my real code, writes to the chipset address space actually go through a function to catch chipset registers addresses. Quote:
Quote:
Quote:
Quote:
Writes to registers like intreq, are more complex functions which implements the bit set/clr function then write the result to the intreqr register (also sets the CPU int level). So an attempt to write to one of the copjmp simply calls the function to reload my internal copperPC with the value of the correct coploc register. This happens immediately. Quote:
Last edited by bloodline; 11 February 2019 at 17:37. |
|||||
12 February 2019, 15:51 | #172 |
Registered User
Join Date: Jan 2017
Location: London, UK
Posts: 433
|
I have done very quick rewrite based upon Toni's comments.
The operation is now 2 (even) cycle, and locks out forbidden registers, freezing operation if a write attempt is made. A call to copjmp1 resets the copperCycle variable to 0 (as well as the copperPC to cop1loc), thus restarting the copper. The copper and blitplane DMA now work! -edit - As a bonus, both Kick1.2 and Kick1.3 now work... Kick 3 just seems to get stuck in a loop. Time to try and get the floppy working again... It was this which prompted the rewrite. Toni, you added a command line option to save out the Raw MFM image to one of the WinUAE beta's for me, would that option be possible as a GUI feature? Cheers. Code:
int copperExecute(){ if((chipset.dmaconr & 0x280) != 0x280){ return 0; } switch(internal.copperCycle){ case 0: internal.IR2 = 0; // DEbug clear the IR2 reg internal.IR1 = internal.chipramW[internal.copperPC>>1]; internal.IR1 = (internal.IR1 <<8) | (internal.IR1 >>8); internal.copperPC += 2; internal.copperCycle = 1; if( (internal.IR1 & 0x1) == 0x1){ internal.copperCycle = 2; } return 1; break; case 1: internal.IR2 = internal.chipramW[internal.copperPC>>1]; internal.copperPC += 2; internal.IR1 = (internal.IR1 >> 1) & 255; // divide by 2 and mask out bad bits... if(internal.IR1<0x20){internal.copperCycle = 4;return 0;}; //pause copper until ned vbl if(internal.IR1<0x40){internal.copperCycle = 4;return 0;}; //as above, but will add in a COPCON test later //Move internal.IR2 = (internal.IR2 <<8) | (internal.IR2 >>8); putChipReg16[internal.IR1](internal.IR2); internal.copperCycle = 0; return 1; break; case 2: internal.IR2 = internal.chipramW[internal.copperPC>>1]; internal.copperPC += 2; internal.IR2 = (internal.IR2 <<8) | (internal.IR2 >>8); internal.copperCycle = 3; //Skip if( (internal.IR2 & 1) == 1){ if( chipset.vhposr >= internal.IR1){ internal.copperPC +=4; } internal.copperCycle = 0; } return 1; break; case 3: //Wait if( chipset.vhposr >= internal.IR1){ internal.copperCycle = 0; } break; case 4: //Copper operation frozen until next VBL break; } return 0; } Last edited by bloodline; 13 February 2019 at 14:51. |
13 February 2019, 20:32 | #173 |
Registered User
Join Date: May 2012
Location: moon
Posts: 208
|
Hi bloodline,
that looks pretty amazing. It is quite entertaining to read through this story. ;-) Can we maybe also peek into the code to get a deeper, e.g. more complete understanding of this DMA sequencer? Are you maybe on GitHub with this Zorro baby ? in any case very cool stuff... ;-) |
13 February 2019, 22:25 | #174 | |
Registered User
Join Date: Jan 2017
Location: London, UK
Posts: 433
|
Quote:
I am happy to share the source code, but it is messy (the memory subsystem is an embarrassment, my clean elegant rewrite didn’t work), there a quite a few bit of test code in there as well, where I haven’t decided exactly how I want to approach the problem. My blitter code works but is clearly buggy (checkout the hand on the kickstart screen and also the intuition gfx), I hope a rewrite to use my new DMA sequencer will do that. I am also happy to go into more detail on any question you have Last edited by bloodline; 13 February 2019 at 22:53. |
|
14 February 2019, 23:35 | #175 |
Out to Grass
Join Date: Jul 2010
Location: UK
Posts: 125
|
Looking good
|
15 February 2019, 09:08 | #176 |
Registered User
Join Date: Jan 2017
Location: London, UK
Posts: 433
|
FYI, I'm just preparing the code for publishing on Github. I have decided to release it under the MPL 2.0 licence... Which I think is reasonable (though I'm not knowledgable about these things).
I spent yesterday trying to get the floppy emulation working, only to realise that it is almost certainly some tiny bug in my blitter code which is causing issue... The error is so subtle, it isn’t noticeable in graphics, but obviously even a single bit error will fail a disk load... So I need someone else to look it over now. Last edited by bloodline; 15 February 2019 at 09:20. |
15 February 2019, 22:41 | #177 |
Registered User
Join Date: Jan 2017
Location: London, UK
Posts: 433
|
The Github link for those interested...
https://github.com/h5n1xp/Omega Oh yeah, I decided to call it Omega for public release, since Zorro already has meaning for us. Last edited by bloodline; 15 February 2019 at 23:02. |
16 February 2019, 10:28 | #178 | |
It's coming back!
Join Date: Jul 2018
Location: comp.sys.amiga
Posts: 762
|
Quote:
|
|
16 February 2019, 10:37 | #179 | |
Registered User
Join Date: Jan 2017
Location: London, UK
Posts: 433
|
Quote:
You will need an MFM ADF (WinUAE can produce these, see back down the thread where Toni added the command line option). -edit- I’m away from my laptop at the moment, but I will post my Linux build script later. It’s just one line this project will compile like compiling any SDL 2.0 code. I had a bootable MFM ADF on my phone, so I’ve added it to the repository: raw2.adf Have fun guys Last edited by bloodline; 16 February 2019 at 10:51. |
|
16 February 2019, 14:51 | #180 |
Registered User
Join Date: May 2017
Location: Munich/Bavaria
Posts: 2,294
|
Hi!
Did you hear about Michal Schulz' approach to bring AROS to the RasPI (big endian) und his new 68K-JIT? The new (alpha) JIT is now reaching over 600MIPS on a RasPI3B+ and he was thinking of some kind of baremetal emulation layer himself: "I need to complete this JIT ASAP and try to integrate it with AROS. Or maybe run the m68k JIT without any operating system directly on RasPi, as a bare metal kernel. What do you think?" So maybe you both should talk? https://www.patreon.com/posts/always-remember-24683131 |
Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
Thread Tools | |
Similar Threads | ||||
Thread | Thread Starter | Forum | Replies | Last Post |
Amiga emulator for iOS | steviebwoy | support.OtherUAE | 35 | 15 November 2014 10:14 |
Amiga emulator for a PSP? | Vars191 | support.OtherUAE | 1 | 09 May 2010 02:08 |
Frederic's Emulator inside and Emulator thread | Fred the Fop | Retrogaming General Discussion | 22 | 09 March 2006 07:31 |
ADF Files -> Amiga(amiga with dos Emulator) | Schattenmeister | support.Hardware | 8 | 14 October 2003 00:10 |
Which Amiga emulator is best? | Tim Janssen | Amiga scene | 45 | 15 February 2002 19:52 |
|
|