Nano SwinSID upgrades (paddles, etc...)

  • Hi everyone,


    First I have to thank x1541 and everybody who contributed for this awesome project known as SwinSID :thanx: you guys rocks! :zustimm:


    However I have found some weird shortcomings of the device, which I think could been easily addressed:


    - support for paddles -- the atmega88 has 2 unused ADC channel which should be used for at least for potentiometer input (lot of musicians use potentiometers connected to paddles to modify sound - mouse support would also be nice)
    - PAL/NTSC (other?) selection -- sampling the computer's clock after reset could be used to set the output's base frequency (the CBM/B machines also use SID at ~2MHZ!!)
    - may be some support for ext_audio_in(?) -- ok, I know it would be more different, and more difficult, but rearranging the pins may free up at least an additional ADC and then maybe it could be processed to simulate the filtering.... (as two pins of PortB only used for the ISP connector, during normal usage these are just wasted, could be repurposed; using external oscillator on PortB6, the PortB7 is also available for I/O)


    I'm yet to know the more in depth operations, but dated and different generation's source codes doesn't helping in the looking for potential optimization/idle cycles to fit in some of the above.


    I've already laid out a board with the paddles connected, but without any pin swapping, so it's still 100% compatible with the older versions.



    What do you think about this?



    cheers,
    ck

  • I think it's a great idea to add the last missing SID functions to the Nano SwinSID. We sometimes have discussions here about re-engineereng a real SID, which is almost impossible or at least extremely expensive, so that in my opinion it is the right way to put more effort into SwinSID to have a device that replaces the SID with new technology and emulates its functions as precisely as possible.

  • Have you seen the http://visual6502.org/images/pages/Commodore_8580_SID.html page and the referenced http://oms.wmhost.com/misc/ address?
    There are a lot of reversing done there, and also very high quality images if you're willing to start that over :)


    But it may not easily reproducible on uC or FPGA environment... (for example you can clearly see the linear cutoff resistors for 6581 and logarithmic resistors for the 8580 )

  • So, I have RE-ed the latest nano SwinSID firmware (sorry, i have forgotten THE MAIN MAN behind SwinSID -- THANK YOU SWINKELS :respect: -- however the lack of source and the polish comments in available older source aren't that nice) and was able to rebuild the binary content to the same.
    Due to the fact, that the Atmega88PA can use more interrupts than INT0 and INT1 -- namely the PCINTx pins, I've managed to reduce the interfacing code quite a bit, by swapping the ~CS and the D2 lines (no more bit-trickery). As the PCINTx-s fire at level change, it required a level check and added an R/W check too, but it was for vain..
    From CS LOW to set the data lines to output and set to zero, took ~450-470nS with the following code:



    As you can see, it did'n even fetch the address, nor the memory at that address. This is the shortest code i can think of to handle read, and it still takes too long to get executed.
    It is really a shame, because of it, SwinSID can never replace the good old MOS SIDs :cry


    Digging deeper into the code also found some leftover(?)/junk(?) codes inside the channel calculations (2-2 section that could never get executed), don't know why are there, but seems to working fine without these.

  • Well, I've been a bit rushed to conclusion as I've only tested the software methods to read the needed registers.
    BUT as the SID only has 4 bytes of read only registers, it can be added by cascaded serial-to-parallel buffers connected to the SPI bus of the Atmega. It needed fiddling with the pins to make room for controlling, access to the SPI output, and the ADC inputs. Actually 3 pins needed from the atmega for the SPI: spi_clk, spi_data, serial-to-parallel_load. There is another pin needed, the output enable, but it is decoded from the ~CS and address lines. The processing of the SPI bus is very simple, after setup any byte written to the SPDR causes that byte to be shifted out, so only a few instruction added doesn't really change the rest of the execution.


    There are some progress in the soft-mode-select too. Using the normally unused 3 bytes it can report identification, and will be used for filter mode select (the pin normally used for this will be used for drain the caps on the motherboard - the atmega's ADCs uses different methods and higher sample rate, so the caps interfere with it)


  • CodeKiller , what does that mean exactly, are things working with your modification, which does not work with normal SwinSID? Do tracks like ´Lazy Jones´ now work with your modifications?


    Don´t know if it is useful, but I have 2 or 3 Beta-Firmwares from Swinkels somewhere here, which were never released, cause in my opinion they sounded poorer than the last released one with only that ´mute-fix´. But maybe they´re useful for you for reverse-engineering...if so, simple send me a pm and I have a look for them.
    Maybe you could ask Swinkels, too for some help, don´t know if he is still active, times ago he was, he also tried some things to improve (the betas here for example) , but without success...his problem was, that he had no programmer at that time to do tests. I do not know what the actual situation is, but if you need some more informations, I am really sure he gives them to you.


    Good work at all, would be totally great to have a full working SwinSid, which also plays the tunes that at the moment does not work.


    By the way, at the moment - with Swinkels firmware - SwinSid does an almost PERFECT job in playing wavefiles through Limonreu-player, it sounds MUCH better/louder than the original Mos-Sid...do your changes affect this functionality, or does it still work as known, without your modifications?

  • @Nobody - in theory it should, but it doesn't fix issues that are purely software dependent.
    As I have looked into this 'Lazy Jones', it does not use the readable registers from the SID, so it must be some other problem. Looking the game trough ICU64+Frodo, it looks that the SwinSID may not like that the ADSR doesn't go to Release phase. (the game always push 0x21 into voice1&2 ctrl registers)


    There is also a problem with 'Master of the Lamps", and that I can't even trace that easy, as the Frodo emu does the same bad sound as the swinsid but the ICU64+VICE lacks the SID debug page. (in memory map, the reading and writing to SID address is observable, but the values doesn't change)


    So yeah, I will look into, if there is a chance to fix.


    I have asked Swinkels about the env3 register location before, but despite the sent schematic and explanation, he only written that it's not possible due to fw limitations. Haven't heard any word from him since that one line of reply back in end of july. (even after I sent the modified firmware too)

  • "Looking the game trough ICU64+Frodo, it looks that the SwinSID may not like that the ADSR doesn't go to Release phase."
    Well, it certainly does go to Release phase, but only for two instruction long ( LDA #$20 -- STA $D40B -- LDA #$21 -- STA $D40B ) --- it may not enough time to go trough a full main loop and update the registers accordingly. And because of that, the swinsid thinks, the gate hasn't been changed so no need to restart the ADSR.....


    Currently I have no idea, how to fix this....

  • @Nobody -- so you wanted 'Lazy Jones'? I just did it :rauch: With this modifications to the code: if a gate 0 received, it saves a corresponding bit to an aux memory too, so in the voice processing if there are no change between the previous and the actual ctrl register the aux bit can still initialize the ADSR to start over.


    It has however a performance impact on the interrupt handling, making the 'fanta in space' glitchy :cursing: (if implemented in the interrupt handling)


    The other method is to regularly check the control registers against the old values and set the aux bits accordingly -- this lead to timing problems (notable pitch differences) and some notes still left undetected (there are ~only 192 avr cycle to catch a rapid gate-closing-opening)
    In sort:
    -interrupt - glitchy Fanta, clean Jones
    -polling - pitch differences, skipping Jones


    Maybe Swinkels could re-tune the pitch? Because the interrupt can't be much longer, or the Fanta sound get distorted.

  • This is very interesting. Just the paddles working is worth the effort.


    So if I correctly understand the problem is that there is no extra processor time to do all that it has to do even with the atmega88 overclocked to 32Mhz...


    Moving to a 32bit AVR may give the extra power to allow this enhancements, and perfect the sound emulation; the smaller one is the AT32UC3C264C-A2UR, but then maybe there should be two swinsid kinds, the Nano SwinSID 2 with working paddles and nothing else more, and the SwinSID Enhanced... more expensive as the AVR is 4 times the price of the atmega88 but with almost perfect SID emulation.


    Or choose a whole different MCU make and start from scratch... :schreck!:

  • The problem is not the speed, but the single pipeline: a real SID does all voice calculation, ADSR, paddle checking, etc.. in simultaneously. So a proper emulation has to clock 100+MHz single pipeline, or using FPGA with the parallel execution.


    The paddles almost works -- the problem is the multiplex - if both c64 joyport is polled, while one is not populated, the capacitor in the mainboard retains some charges and fools the ADC circuit in the AVR, so i think it should be discharged before sampling.




    Holy quackamoly --- just did the (almost) impossible - proper Fanta AND Lazy Jones :thumbsup: (well there are still some quirks)
    The trick is to handle as little in interrupt as possible while signaling the changes: if the incoming data ends with 0 bit, it saves the address to a temp register and in some places in the main loop it checks if the address is indeed a ctrl one. Then it sets the extra gate bits in another reg and clears the temp address after.

  • simultaneously, that means in serial very fast, since the sid "oscillators" are only in audio range up to maximum ~4 kHz, they would have to be updated in an interrupt at that frequency minimum. also all other functions can be solved either mathematical or by enabling a timer that checks if it is enabled and then counts down the value (like ADSR). the challenge is to simulate the behaviour of non hardrestart tunes being played, in terms of wave duty cycle when attack kicks in. also ADSR restart bugs would have to be implemented.


    i would say it is a dead end road to try to emulate the 6581 (or even 8580) filter properly on the atmega, as digital filters just have different linear and digital characteristics. i would go for a hybrid solution, a discrete built up digital controlled mulitmode analog filter (1x LP, 1X BP, 1xHP), where all the oscillators and envelopes are generated in the atmel, and filter cutoff and resonance (=feedback) is this external discrete circuit controlled by the atmel with control voltages. all the quirks like filter distortion curves could be implemented in the atmel and the filter can be controlled to simulate exact behaviour. it may be a huge effort hardware wise, but a better approach to a "true" sound.


    the other option would be to switch to a more powerful atmel or even another platform and try to mimic the filter there.


    and the last option is, to say the filter sounds good like it is now.

  • since the sid "oscillators" are only in audio range up to maximum ~4 kHz, they would have to be updated in an interrupt at that frequency minimum

    You have forgot, that there is a wider range in the osc than divides of 4kHz. --- also no one said anything about filter upgrade...


    I think the current SwinSID works well enough, but can be improved.



    Back to the topic -
    Current pending issues:
    - unnoticed ADSR restart while maintaining a sort enough interrupt handler (with external clock divider a few instruction can be omitted)
    - ADC support for 2-out-of-4 paddle mode
    (maybe external sound in)
    - soft setup instead of the filter-select pin
    (- soft setup for other values)


    Current solved issues:
    - env3 reading
    - osc3 reading
    - swinsid identification
    - partial ADC support (without multiplex or with 4 paddles -- needs a discharging circuit)
    - partial support for ADSR restart (needs to properly distribute the checks in the main loop, or find another solution)

  • yes true, to get the full 16bit range maybe more speed is needed.


    and the thing about the filter is just my personal 2 cent opinion i am expressing here, sorry if you are disturbed by such "off topic" postings.


    i thought this thread is the only place at the moment where some people with skills are gathered to update swinsid, thats why i mentioned what i would try if i had your skills and programming passion.


    i tried the nano myself and i was really amazed of the sound, but only until i tried to play tunes that use the filter a bit more dedicated. it could be really awesome when the filter worked better. ok BTT then ;)

  • Oh slap :platsch: why I used another register if the addresses has been saved?! Now i just check it in the corresponding voice control register check if the address is for that voice. It may be sux, if more voices has been cleaned in this way in rapid succession, but luckily in 'Lazy Jones' that's not the case - so it sounds perfect (as far as emulation goes).
    Only minor problems remained in 'Fanta' - some voices doesn't cut off (most notable at the loop end) ---- maybe a clk divider in the interrupt pin could help by reducing the interrupt handler (as now i'm using a PCINT which is fires on both edge and the handler has to check if it was indeed a falling one or not)


    This is how you think outside of the box - cannot handle read ->put in serial-to-parallel buffers / can't detect rapid gate change -> store in a register the address of the last input byte that ended with 0 bit / can't have long int handling -> shrink the code with added circuit.



    oneBitman : i don't know what's your problem with the filter ... bit crusty, but still better than the C64DTV :P - but seriously, the 'Fanta in space' uses the filters quite intensely and it sounds good enough for me (well, it's 8580 optimized, not to your fancy 6581 R1-2-3-4 magic date code ones..)


    The SwinSID is a small, budget replacement to original machines. These upgrades still very cheap, and may be laid out in the same space (with double load). So this upgrades are only viable, if not require more expensive stuff than the swinsid itself.


    More precise emulation/replacement has to be done on an FPGA with analog supporting circuit (filter) or better DSP quality but it's should be an entirely new/revived project (like V-SID and others).

  • CodeKiller - thanks for your efforts in improving SwinSID. I'm afraid adding reading support will be impossible without additional hardware and that was the reason I abandoned this. I wanted to make it as simple as possible. The main problem now is compatibility with some tunes like Lazy Jones or Bomb Jack. I have analyzed these tunes some time ago, and today I did this once again. Indeed, the Lazy Jones disables gate bit only for a couple of cycles and SwinSID which usually misses. To fix this interrupt handler must track all gate bit changes. The fix for Lazy Jones was added to the source at least two years ago, but there was some side effects and I removed this from official releases. I can't remember what were exactly the problems but now I'm publishing new test firmware for additional testing. CodeKiller - please look at the interrupt handler and compare it with your solution. Maybe we can work out the final version of fix. The firmware is for ATMEGA88 chip and was not tested on a real device!. It may be completely broken. Please consider this when flashing.
    test1 - latest source + old patch - it checks for gate change from 0 to 1 and sets attack flag
    test2 - latest source + new optimized patch - it stores copy of control register only when it contains 0 in gate bit.

  • Dear Swinkels -- come on, Hex files only? Really?? I had hard time RE-ing one, i won't look into two more, thank you.....


    But for what you've written - the check from 0 to 1 makes no sense --- the problem lies in the switch off / transition to gate 0 -- when the gate is in 1, it needs time for the SID too to make sound, the main loop is able to pick it up, but if the ADSR has already reaches 0, in theory it doesn't need time to restart, just a very brief gate 0 and that's where the loop can miss.
    copy the ctrl register --- i've done this in two versions ago -- but look op again my last post -- you doesn't have to handle it in the interrupt handler, just 3 more command in the handler:

    Code
    1. sbrc sid_data, 0
    2. reti
    3. mov r28, sid_addr
    4. reti


    You have time later in the main loop to check if it was really an interesting one, or just junk. But wait, you don't have to check it often, just in the ADSR start for the corresponding address.

  • Maybe we can work out the final version of fix.


    More track-compatibility would be fantastic :)


    In my opinion the soundquality of the SwinSid is ok, only thing I could complain about is that some tracks (->Lazy Jones) won´t work...lets hope that you both together find a solution ^^