gideonz / 1541ultimate Goto Github PK
View Code? Open in Web Editor NEWOfficial GIT archive of 1541 ultimate II sources
License: GNU General Public License v3.0
Official GIT archive of 1541 ultimate II sources
License: GNU General Public License v3.0
On Fri, Feb 16, 2018 at 11:14 AM, I wrote:
I thing your analysis from My 21th, 2017 is right:
As described in the document, there are three ways to freeze the CPU, of which the safest is to wait for a bad line and then just set the DMA line and wait for BA to become high. This way, the bad line was correctly started by the VIC, and we just extend it indefinitely.
I must admit that I do not know what exactly happens in 2 MHz mode. Obviously, the VIC fetches are given a lower priority. I'd say that the bad lines do not occur anymore at all, but I haven't done measurements to confirm this.
If bad lines don't occur, the Ultimate hardware will wait for the next most feasible solution, which is waiting for three writes in a row; which happens when an interrupt occurs. However, in 2 MHz mode, these three writes do not happen in three consecutive cycles, but they appear at three consecutive HALF-cycles, so the Ultimate won't recognize this.
Most likely, the Ultimate will fall back to the third, unsafe option: just assert DMA and accept the chance of losing a write cycle from the CPU. This may indeed lead to random crashes. It MAY even be so that this method incorrectly breaks a read cycle, because 2 MHz timing is not considered. When a read fails, you know what will happen: upon continue, any opcode / operand might be corrupt, your program might crash right there and then.
The tools program instructs the user to press the WRITE_PROTECT button and then the reset button on the HD to enter configuration mode. But when UII+ cart is plugged in, it returns with "System is not set for reconfiguration" and then halts.
Removing the cart causes it to work normally. Is there at least any way to disable the cart and reenable it later?
Is it possible to have an ML monitor on the application code side, which will allow you to single step through code? This would be an incredible addition to the U64 when the UI is in overlay mode. Im sure an ML monitor could be written to read and modify memory contents based on what I see in the code - its the single stepping that Im wondering about. If not possible, we can close this issue.
Locate a D64 image, hit enter, menu pops up (Mount Disk, Run Disk, etc). Select View. The logical assumption is that this will let you see the disk directory, but its empty. V3.3 (112)
The 1.18 firmware is the best firmware yet for the U64. Using a physical fastload cartridge like the Retro Replay, Action Replay, Final Cartridge II and even the MMC Replay seem to work stable with the U64 now (or perhaps even already since v1.10?).
When using the U64 with a physical cartridge I noticed unexpected behaviour I haven't noticed before.
The steps to reproduce:
The result is that the Ultimate will boot to a vanilla C64 instead of a C64 with the fastload cartridge plugged in. When pressing the reset button on the physical cartridge it will make the U64 reset again... into a vanilla C64. The same happens when I reset the U64 using the power button.
To correct this, I need to go into the Ultimate Menu, press F5 and choose "reboot c64".
Whenever I load and run a programme using the physical cartridge, the U64 does not (seem) show the behaviour above. In other words, then it works as I would expect.
The Easyflash specification allows to save things on the cartridge.
This is a feature more and more cartridge releases use. Since the 1541 does not support it yet, saving a game is impossible for recent releases.
So, it would be great to support the full Easyflash specitications.
For example, some releases that make use of the save feature:
https://csdb.dk/release/?id=156948
https://csdb.dk/release/?id=98674
It would be nice to have an option to do the cross-connecting described here:
http://a1bert.kapsi.fi/Dev/burst/
As a menu option, vs having to take a soldering iron to my Ultimate64. For those of us who have a 1571 drive around, and a few disks, being able to read MFM and faster disk access is nice.
when doing:
make u64
I get the following:
Making all requires output, result and result/ultimate.app result/ultimate.elf output/ultimate.sim
make[1]: Leaving directory '/home/scott/1541ultimate/target/software/nios2_u64'
make[1]: Entering directory '/home/scott/1541ultimate/target/software/nios2_update_u64a4'
make[1]: *** No rule to make target 'u64.sof', needed by 'output/u64.pof'. Stop.
make[1]: Leaving directory '/home/scott/1541ultimate/target/software/nios2_update_u64a4'
Makefile:179: recipe for target 'u64' failed
The basics of this one is that I have a program which tries to load a config file from the device which loaded the program. Ive set the DMA Mimics Device ID: 11. And the virtual drive is 11. But when I select RUN from the menu to execute the program, it locks up trying to read the config file.
The program knows the device id properly. So something is weird with maybe initializing the drive. The only way I can really give you more info on this one (without making you read my code) would be to put together a youtube video demonstrating the issue. Let me know if you need that or if this makes sense. Im working on an update to the terminal program that will read from a phonebook, and most people will probably be selecting it and RUN directly from the U64 menu. I could force them to use a D64 image of it, if thats the only workaround right now. (which works as expected).
On the current U64 firmware build (V1.10 Official 3.4) the Ultimate 64's 'Capture Save to Tape' option tries to capture a save to .tap image, but after finishing saving, and refreshing the directory. A 20kb .tap image is made, which is incomplete. There's probably a bug in this area.
10 PRINT "HELLO WORLD"
20 GOTO 10
SAVE"HELLO"
and using "Capture SAVE TO TAP" creates a TAP file that cannot be read.
Ive tracked this down to iec_channel.h:
` int read_dir_entry(void)
{
if(dir_index >= dir_last) {
buffer[2] = 9999 & 255;
buffer[3] = 9999 >> 8;
memcpy(&buffer[4], "BLOCKS FREE. \0\0\0", 28);
last_byte = 31;
pointer = 0;
prefetch_max = 31;
prefetch = 0;
return 0;
}
printf("Dir index = %d %s\n", dir_index, (*interface->iecNames)[dir_index]);
FileInfo *info = (*interface->dirlist)[dir_index];
//printf("info = %p\n", info);
uint32_t size = 0;
uint32_t size2 = 0;
if(info) {
size = info->size;
}
size /= 254; <-----------------------------this line
if(size > 9999)
size = 9999;
size2 = size;`
When that line is as-is, VFS file sizes are correct, but when you cd into a D64 image, they report zero for all files. Commenting that line out, gives proper file sizes inside D64 images, but incorrect sizes in the regular VFS. Catch-22 or am i reading this wrong?
I have a disk as 9, and 10 is disabled. When selecting a d64 image, then RUN, it unfreezes, but sends LOAD":*",8,1 instead of 9,1. Minor issue, but just thought you might want to know.
I've just got the following bug report - which I just translated to english:
I have installed the latest firmware 3.3_180912+_v1 (1x drive, audio) on my 1541 Ultimate II.
Computer: C64 Reloaded MK2
Now the demo "Deus Ex Machina" does not run, stops at "Big Breadbox is wathing you".
Red LED on the module does not go out...
Generally starting from firmware 3.3 - Does not run the above demo with me any more...
With the firmware 3.2a_180411+_v1 the above demo works fine.
NOTE: This might be due to voltage dips!
I have an NTSC "slim breadbin" from around the end of 1986 with a UP9600 modem installed. Very rarely, pressing the menu button brings me to the menu, but all the text will be a pink, garbled mess. Going back to the basic prompt from here slices off the first usable column of text on the left side, and (even rarer) switches video modes to make the BASIC prompt look like pea soup. In Final Cart III mode, a purple mess replaces the cursor on the menu screen...
Not sure what's going on here. I've cleaned the contacts on all ports, the cart slots, and more, but it seems to be graphical corruption more than anything else. Switching the C64 off and back on again usually fixes the issue. I'm going to be checking the caps on my board to see if there are any failing ones that only get fussy when that much power is being drawn through from all the attachments.
The keyboard on my native c64 had a broken key why I started using an external keyboard, and with the keyboard fixed, I still prefer that setup.
However, whereas Ultimate64 gracefully supports the native Swedish keyboard and Swedish kernal keymap, it doesn't support the external keyboard equally gracefully. I assume here that it assumes all external keyboards are US keymap.
Being concerned that Gideon shall focus on stuff that is of importance, my suggestion is support for some sort of existing keymap format. Microsoft uses .KLC and also provides an editor in case you want to make your own variant [1]. I'm sure there are other file formats for other platforms, but the main point here would be that it would be great if one was just able to import established files rather than relying on building similar files from scratch for all relevant languages.
[1] https://www.microsoft.com/en-us/download/details.aspx?id=22339
On an external USB keyboard,the numeric keyboard returns the numbers and NumLock has no effect.
Alternative 1: On a standard PC keyboard, NumLock toggles between numeric keyboard and using the keys for cursor movement.
Alternative 2: Using an emulator on a bigger system, a standard option is using the numeric keyboard as joystick. With an external USB keyboard, I would like to suggest having NumLock toggle between numeric keyboard (default - as it works today) and joystick emulation (new feature). (Enough keys to allocate a few to other purposes - "'-" for swapping port 1/2 and "+" for autofire?)
Here I would vote for Alternative 2.
The games start up image is shown but nothing else happens after that.
$ shasum SBB64K.crt
9cf83f7402fe01a107b839472a6d42e609b29aff SBB64K.crt
download game here (free) http://rgcd.bigcartel.com/product/super-bread-box-commodore-64
The same .crt + jiffydos roms works well with 1541u2+ and c64 reloaded mk2
It would be more consistent with sd2iec devices (making programming common between devices) if we could see disk images as their file types. For instance "MYDISK.D64" would have a D64 file type. D71, D81, etc. Right now, anything that isnt a program shows up as a SEQ file type (or DIR). Unknown file types could be "UKN" or "???"
When resetting the U64, using the four left modifiers (Shift-Ctrl-Alt-Windows) on a USB keyboard, does only reset the CPU as it seems, not the cartridge. So it resets to a standard basic screen, instead of the cart that is currently enabled, like RR.
I came across some CRT images that did work on the Vice Emulator, but did not work with the 1541 Ultimate 2. I tried on both C128 and C64 with the nms settings that usually work.
Here is one of these images for example.
alieninfilt1.zip
MIDI in and or out support would be great, some trackers support MIDI to various extents.
This issue is primarily for gathering requirements and documentation
There are a bunch of midi interfaces for C64, most are cartrigdes, at least one of them are IEC based. A MIDI circuit design is very simple, mostly just an UART with a resistor and an opto isolator so some kind of extension board would probably be preferred.
I would want a solution that works for the largest possible user base, I don't know which trackers people are actually using these days but my research focus will be on SID-Wizard and defMON for the time being.
reference: http://www.c64midi.com/C64midi/Interfaces/Interfaces.html
https://csdb.dk/release/?id=126812
A pic based MIDI input circuit which is connected via the IEC bus.
Note: this device draws 5v from the MIDI host which IIRC is not in the MIDI
spec so this device might not always work.
A MIDI in/out/thru cartridge.
schematics + source code: https://github.com/FrankBuss/kerberos/
info page: http://www.frank-buss.de/kerberos/index.html
schematics + avr firmware source: https://github.com/kiwanowski/defmon-sync
defMon Sync Adapter is an adapter for the Commodore 64 computer. It is used to synchronize a tracker called defMon with other music equipment. It connects to the user port and outputs the following signals:
It can only work as the master.
It should also work with Prophet64.
Since this interface is connected to the user port it can coexist with 1541u without having to use multiple cartriges so it's probably not something that is terrible interesting to implement inside of u1541
reference: http://chordian.net/c64editors.htm
defMON support generating clock sync to DINsync/MIDI using defmon-sync.
SID-Wizard supports MIDI note input with a large range of hardware interfaces.
;Multi-device MIDI-input library for the Commodore 64
;supports: HerMIDI, Sequential (SCI), Passport/Syntech,
; Datel/JMS/Siel/C-LAB, Namesoft, Maplin, Moog Song Producer
receives midi notes and plays them directly
http://www.qotile.net/cynthcart.html
http://csdb.dk/release/?id=142049
DATEL/SIEL/JMS/C-LAB PASSPORT/SENTECH SEQUENTIAL/NAMESOFT HERMIDI
To avoid creating new circuitry a solution might be to add support for class compliant USB midi devices in the firmware.
;ident:8,24
;=======================================================================
;Multi-device MIDI-input library for the Commodore 64
;supports: HerMIDI, Sequential (SCI), Passport/Syntech,
; Datel/JMS/Siel/C-LAB, Namesoft, Maplin, Moog Song Producer
;Year:2014, code: Mihaly Horvath (Hermit), NameSoft-info: Frank Buss
; $Id: MIDI-C64.asm 360 2014-02-15 14:50:28Z soci $
;=======================================================================
;====================== MIDIC64 External Settings ======================
.weak
MIDIC64_EXT_SETTING = 0
.endweak
.if !(MIDIC64_EXT_SETTING) ;if caller program sets it,inherit settings
MIDIC64_EXT_SETTING=0 ;upcoming settins for memory footprint reduction
MIDIC64_TX_ENABLE=0 ;whether to support Transmitting MIDI-data or not
MIDI_Legacy_support=1 ;standard/legacy extension-port devices using ACIA
MIDIC64_INC_EVENTS=1 ;whether 'EVENT' & 'GetEvent' routine is needed
MIDIC64_INC_NAMES=0 ;include names of devices?
MIDIbuffer_size=32 ;should be bigger than HerMIDI.MaxBuffSize (it uses)
MIDIC64_Watchdog_ini=200 ;0:no watchdog, 1..$ff: init value of watchdog
HerMIDI_support=1 ;enables support for HerMIDI Serial/IEC-port device
.if (HerMIDI_support!=0)
HerMIDI_TX_MODE = MIDIC64.HerMIDI.AsyncMode
HerMIDI_PacketSize=MIDIC64.HerMIDI.MaxBuffSize
.fi
.fi
.weak
HerMIDI_INC_SYNCHR=1 ;if nonzero: synchron-mode READ gets included
HerMIDI_INC_ASYNCH=1 ;if nonzero: asynchron-mode READ gets included
HerMIDI_INC_DIRECT=0 ;if nonzero:DirectMode READ (DirecRx) gets included
HerMIDI_INC_EVENTS=0 ;if HerMIDI's 'GetEvent' routine included
MIDIdev=MIDIC64.DeviceID
NMI=MIDIC64.RTIcode
IRQ=MIDIC64.RTIcode
MIDIbuffer=MIDIC64.EventBuffer
.endweak
;=======================================================================
MIDIC64 .block
;================ MIDIC64 Internal Constants & Settings ================
.if (MIDI_Legacy_support!=0)
;Control-Register's bits in Expansion port devices using ACIA chip:
RxIntEnable= bit7 ;1:Enable Receive-Interrupt, 0:Disable Rx-Interrupt
TxControl = bit6 ;1:Transmits a Break level on the Transmit Data Output
TxIntEnable= bit5 ;1:Enable Transmit-Interrupt, 0: Disable Tx-Interrupt
WordSelect= 1*bit4+0*bit3+1*bit2 ;'101': 8 bits, no parity, 1 stop-bit
MIDIreset = 1*bit1+1*bit0 ;#03 to 'MIDIcontrol' register resets the ACIA
;Status-Register's bits in Expansion port devices using ACIA chip:
IntRequest = bit7 ;Set 1 when: RxDataRfull/TxDataRempty/RxOverrun is on
ParityError = bit6 ;Set 1 on parity-error if 'WordSelect' has parity set
RxOverrun = bit5 ;Is set to 1 when byte(s) were lost in data-stream
FramingError= bit4 ;Set 1 if latest received character improperly framed
ClearToSend = bit3 ;0:MIDI-device ready to receive, 1:MIDI-dev not ready
DataCdetect = bit2 ;0:no byte, 1:databyte interrupt,read Status to clear
TxDataRempty= bit1 ;Set to 1 when TX-register is ready for writing.
RxDataRfull = bit0 ;Set to 1 when RX-register is ready for reading.
MIDI_Legacy_list = [Sequential, Passport, DatelJMS, NameSoft, NameSoftIRQ, Maplin, MoogSP]
.else
MIDI_Legacy_list = []
.fi
Sequenti_support=1*MIDI_Legacy_support
Passport_support=1*MIDI_Legacy_support
DatelJMS_support=1*MIDI_Legacy_support
NameSoft_support=1*MIDI_Legacy_support
NameSoftIRQ_support=1*MIDI_Legacy_support
Maplin_support = 1*MIDI_Legacy_support
MoogSP_support = 1*MIDI_Legacy_support
;MSSIAH_support=0 ;no tech. info, probably in 'Legacy' group as well
;MIDI-device identifiers:
HerMIDI_ID=1 ;number/ID of HerMIDI device
Legacy_min=2 ;number/ID of 1st device in Legacy-category
Legacy_max=Legacy_min+len(MIDI_Legacy_list)-1;Legacy-cat.max.ID
IRQmode=$40
NMImode=$80
;============================= JUMPTABLE ===============================
.if (*==$0000)
*=$C000 ;for standalone-build (pre-compiled form)
OPEN jmp OpenDev ;don't forget to set Accumulator before (ControlCmd)
READ jmp GetData ;'OPEN' should preceed,automatically selects Tx-mode
CLOSE jmp CloseDev
EVENT jmp GetEvent ;'jsr READ' should preceed this call to fill buffer
;Base Address+: 0:OPEN, 3:READ, 6:CLOSE, 9: EVENT
.fi
;======================== Variables, Arrays ============================
;Base Address+: $0c: Status, $0d: device-type/ID (if jumptable before)
Status .byte $ff ;if zero, all OK, if nonzero it's error-code
DeviceID .byte 0 ;MIDI-hardware type ID
;names corresponding to device-IDs (usable by caller programs)
EventBuffer .proc
.fill MIDIbuffer_size,0
.pend
.if (MIDIC64_INC_NAMES!=0)
DeviceAmount=size(DevName)/8-1
.enc screen
DevName .text " NONE ","HERMIDI ",MIDI_Legacy_list.DevName
.enc none
.else
DeviceAmount=Legacy_max
.fi
.if (MIDI_Legacy_support!=0)
MoogSP_ID=8 ;Used to distinguish Moog Song Producer device at init/close
ControlAdd .word MIDI_Legacy_list.MIDIcontrol
StatusAddr .word MIDI_Legacy_list.MIDIstatus
RxAddress .word MIDI_Legacy_list.MIDI_Rx
;TxAddress .word MIDI_Legacy_list.MIDI_Tx
InitDevVal .byte MIDI_Legacy_list.MIDIenable
IntrptType .byte MIDI_Legacy_list.IntType
IenableVal .byte MIDI_Legacy_list.IRQenable
IenableVal_end
rdCtrl lda selfmodA
rts
wrCtrl sta selfmodA
rts
rdStat lda selfmodA
rts
wrStat sta selfmodA
rts
.if (MIDIC64_Watchdog_ini!=0)
watchdog .byte MIDIC64_Watchdog_ini;to prevent loop,main-prg sets in every 20ms
.fi
.fi
;*********************** MAIN CROSS-HW ROUTINES ************************
;-------------------------------- OPEN ---------------------------------
OpenDev .proc ;reads control-info in A, opens/turns on MIDI-device
.if (MIDIC64_INC_EVENTS!=0)
lda #0
sta GetEvent.ValuCnt+1 ;maybe we're in the middle of databytes
sta GetEvent.CmdLeng+1
lda #MIDI.Undefined ;so prevent processing them after init
sta GetEvent.Command+1
.fi
ldx MIDIdev
beq retOpen ;0 means no/dummy MIDI-device
cpx #Legacy_min
bcs chLegac
.if (HerMIDI_support!=0)
OpenHM lda #HerMIDI_TX_MODE+HerMIDI_PacketSize
jmp HerMIDI.PowerON ;OPEN
.else
rts
.fi
chLegac cpx #Legacy_max+1
bcs chOther ;could go to other upper categories later
.if (MIDI_Legacy_support!=0)
OpenLgc ;open standard/legacy MIDI-devices
SetAddr txa ;MIDI-device-number in X
asl ;*2
tay
lda (ControlAdd-Legacy_min*2)+0,y
sta rdCtrl+1
sta wrCtrl+1
lda (ControlAdd-Legacy_min*2)+1,y
sta rdCtrl+2
sta wrCtrl+2
lda (StatusAddr-Legacy_min*2)+0,y
sta rdStat+1
sta wrStat+1
sta GetData.StatusB+1
lda (StatusAddr-Legacy_min*2)+1,y
sta rdStat+2
sta wrStat+2
sta GetData.StatusB+2
lda (RxAddress-Legacy_min*2)+0,y
sta GetData.RxByte+1
lda (RxAddress-Legacy_min*2)+1,y
sta GetData.RxByte+2
Reset lda #MIDIreset
jsr wrCtrl
lda InitDevVal-Legacy_min,x ;set MIDI-device, disable NMI/IRQ
jsr wrCtrl
jsr SetMIDIintA
clrBuff lda #0 ;clear MIDIbuffer
.if (MIDIC64_INC_EVENTS!=0)
sta GetEvent.rdIndex+1
.fi
sta GetData.WrIndex+1
chkStat jsr rdStat
and #ClearToSend ;check if init successful
sta Status
bne retLega ;if unsuccessful, don't enable NMI/IRQ
startRx lda IenableVal-Legacy_min,x ; enable NMI/IRQ from MIDI interface
jsr wrCtrl
cpx #MoogSP_ID
bne retLega
lda #MoogSP.Control_Enable
sta MoogSP.Control_Latch1
retLega rts
.fi
chOther ;no other devices yet...
retOpen rts
.pend
;-------------------------------- READ ---------------------------------
GetData .proc ;reads databytes and puts them into MIDI-databuffer
ldx MIDIdev
beq retData ;0 means no/dummy MIDI-device
cpx #Legacy_min
bcs chLegac
.if (HerMIDI_support!=0)
.if (MIDIC64_INC_EVENTS!=0 && HerMIDI_INC_EVENTS==0)
lda #0 ;HerMIDI's buffer is not a ringbuffer
sta GetEvent.rdIndex+1
.fi
jmp HerMIDI.GetData ;READ
.else
rts
.fi
chLegac cpx #Legacy_max+1
bcs chOther ;could go to other upper categories later
.if (MIDI_Legacy_support!=0)
retLega rts ;nothing to do,IRQ/NMI based MIDI-devices use InterruptGetByte/etc
.fi
chOther ;no other devices yet...
retData rts
.if (MIDI_Legacy_support!=0)
InterruptGetByte
pha
lda banksel
pha
lda #$35 ; enable IO
sta banksel
StatusB lda selfmodA ; test if it was a NMI/IRQ from the MIDI interface
;bpl + ;if not, give control to host program's interrupt
chInput and #RxDataRfull ;test if note at input. If not, probably pulled off
bne stInput ;if no input cable maybe pulled off, prevent freeze?
+ pla ; restore previous bank selection and end IRQ
sta banksel
pla
HostInt jmp selfmodA ;jmp NMI/IRQ-continue with host-program's interrupt
stInput txa
pha
RxByte lda selfmodA ; get MIDI byte and store in MIDIbuffer0
WrIndex ldx #selfmod
sta MIDIbuffer,x
inx
cpx #MIDIbuffer_size
bcc +
ldx #0 ; this makes it behave as a ring-buffer
+ stx WrIndex+1
.if (MIDIC64_Watchdog_ini!=0)
dec watchdog
bne IntEnd
tya
pha
jsr CloseDev
pla
tay
.fi
IntEnd pla ; restore previous bank selection and end IRQ
tax
IntEnd2 pla
sta banksel
pla
.fi
.pend
RTIcode rti ;check if not defined yet externally
;------------------------------- CLOSE ---------------------------------
CloseDev .proc ;disables / turns off the MIDI-device
lda #$ff ;sign that device is switched off
sta Status
ldx MIDIdev
beq rtClose ;0 means no/dummy MIDI-device
cpx #Legacy_min
bcs chLegac
.if (HerMIDI_support!=0)
jmp HerMIDI.PowrOFF ;CLOSE
.else
rts
.fi
chLegac cpx #Legacy_max+1
bcs chOther ;could go to other upper categories later
.if (MIDI_Legacy_support!=0)
CloseLg lda #MIDIreset ;InitDevVal-Legacy_min,x ;disable NMI/IRQ
jsr wrCtrl
cpx #MoogSP_ID
bne SetIntA
lda #MoogSP.Control_Disable
sta MoogSP.Control_Latch1
SetIntA lda IntrptType-Legacy_min,x
bmi +
jsr LdIRQad
jmp setIRQ
+ jsr LdNMIad
jmp setNMI
; lda #<ROMRTI ;dummy, if host-program's NMI is under ROM
; ldy #>ROMRTI
; jmp setRNMI
;retLega rts
.fi
chOther ;no other devices yet...
rtClose rts
.pend
;------------------------------- EVENT ---------------------------------
GetEvent .proc ;reads an event from the buffer to A,X,Y; C=1 if read out
.if (MIDIC64_INC_EVENTS!=0)
ldx MIDIdev
beq rtGetBy ;0 means no/dummy MIDI-device
cpx #Legacy_min
bcs chLegac
.if (HerMIDI_support!=0)
.if (HerMIDI_INC_EVENTS!=0)
jmp HerMIDI.GetEvent
.else ;in MIDIC64 HerMIDI uses this instead of its own
lda HerMIDI.BuffIndex
jmp GetLevn
.fi
.else
sec ;tell host program there's no event for HerMIDI
rts
.fi
chLegac cpx #Legacy_max+1
bcs chOther ;could go to other upper categories later
.if (MIDI_Legacy_support!=0 || (HerMIDI_support!=0 && HerMIDI_INC_EVENTS==0))
lda GetData.WrIndex+1
GetLevn sta chIndex+1
rdIndex ldx #selfmod ;keeps track where we are reading in the buffer
ValuCnt ldy #selfmod ;stored remaining amount of value-bytes
chIndex cpx #selfmod ;stored value of buffer write-index
bne rdEbyte ;sets Carry-flag=1 if buffer is read out and exits
BuffEnd sty ValuCnt+1 ;we'll pick up in next round where we left off
rts
rdEbyte lda MIDIbuffer,x
bpl StorVal ;status (command above $7F) or value (below $80) ?
cmp #MIDI.RealTime_min ;transparent (command not stored)
bcs AdvBuf3 ;if above (RealTime Messages), set Accumulator only
StorCmd sta Command+1
chkOMNI cmp #MIDI.OMNI_min ;all system messages will return immediately
bcc VoicMsg
ldy #0 ;System messages cancel 'running status' mode
sty CmdLeng+1
jmp AdvBuf3
VoicMsg ldy #2 ;Y=2 ;pre-set for MIDI-commands that have 2-byte value
and #%11100000 ;check bit5 and bit6 ($20 + $40), plus bit 7
cmp #%11000000 ;if '110' it's $Cx or $Dx with only 1-byte value
bne +
dey ;Y=1
+ sty CmdLeng+1 ;store length for 'running status' that may come
jmp AdvBuf2
StorVal cpy #1 ;check if Y is 0 or 1 or 2 (0:'running status' case)
bpl + ;if Y != 0 (Y>=1), check which databyte to send
CmdLeng ldy #selfmod ;Y was 0,'running status', reusing previous command
bne StorVal ;retain previous non-transparent status-byte (cmd)
+ beq StoVal2 ;if Y is 1, only the 2nd databyte is left
StoVal1 sta Value1+1
dey ;advance to Value2;(Y=1 for MIDI-commands with 1-byte value)
AdvBuf2 inx ;advance in buffer
cpx #MIDIbuffer_size
bcc +
ldx #0 ;this makes a ring-buffer behaviour for legacy devices
+ jmp chIndex
StoVal2 ldy #0
sty ValuCnt+1 ;initialize databyte-counter for next message
tay ;Y=Value2
Command lda #selfmod
AdvBuf3 inx
cpx #MIDIbuffer_size
bcc +
ldx #0 ;this makes a ring-buffer behaviour for legacy devices
+ stx rdIndex+1
Value1 ldx #selfmod ;and Value2 is Y
clc ;tell caller that reading the buffer is not yet over
rts
.fi ;end of checking MIDI_Legacy_support
chOther ;no other types of devices yet...
.fi ;end of checking MIDIC64_INC_EVENTS
rtGetBy sec
rts
.pend
;-------------------------------common---------------------------------
.if (MIDI_Legacy_support!=0)
SetMIDIintA lda #<GetData.InterruptGetByte
ldy #>GetData.InterruptGetByte
SetIntA pha ;inputs: X=DeviceID, A=low-addr, Y=hi-addr
lda IntrptType-Legacy_min,x
bmi setNMIg
setIRQg pla
jsr setIRQ
LdIRQad lda #<IRQ
ldy #>IRQ
jmp +
setNMIg pla
jsr setNMI
LdNMIad lda #<NMI
ldy #>NMI
+ sta GetData.HostInt+1
sty GetData.HostInt+2
rts
setIRQ php ;store I-flag
sei ;disable interrupt during setting
sta $fffe
sty $ffff
plp ;restore I-flag
rts
setNMI sta $fffa
sty $fffb
setRNMI sta $0318 ;because NMI can even happen while ROM is turned on
sty $0319
rts
.fi
;******************* Device-specific values & codes: *******************
;========================== HerMIDI object =============================
.if (HerMIDI_support!=0)
HerMIDI.INC_SYNCHR = HerMIDI_INC_SYNCHR
HerMIDI.INC_ASYNCH = HerMIDI_INC_ASYNCH
HerMIDI.INC_DIRECT = HerMIDI_INC_DIRECT
HerMIDI.INC_EVENTS = HerMIDI_INC_EVENTS
HerMIDI.Status = Status
HerMIDI.MIDIbuffer = MIDIbuffer
HerMIDI .binclude "HerMIDI/HerMIDI-C64.asm" ;contains HerMIDI-device's routines
.fi ;end of HerMIDI_support checking
;========================= Sequential object ===========================
.if (Sequenti_support!=0)
Sequential .block
DevName = "SEQUENTL"
MIDIcontrol = $de00 ;write-only
MIDIstatus = $de02 ;read-only
MIDI_Tx = $de01 ;write-only
MIDI_Rx = $de03 ;read-only
MIDIspeed= 1
CounterDiv = (MIDIspeed==1) ? 0*bit1+1*bit0 : 1*bit1+0*bit0;div by 16/64
MIDIenable = WordSelect+CounterDiv ;IRQ is disabled with this value
IRQenable = RxIntEnable+WordSelect+CounterDiv
IntType = IRQmode
.bend
.fi
;========================== Passport object ============================
.if (Passport_support!=0) ;PASSPORT/ (SYNTECH is the same)
Passport .block
DevName = "PASSPORT"
MIDIcontrol = $de08 ;write
MIDIstatus = $de08 ;read
MIDI_Tx = $de09 ;write
MIDI_Rx = $de09 ;read
MIDIspeed= 1
CounterDiv = (MIDIspeed==1) ? 0*bit1+1*bit0 : 1*bit1+0*bit0;div by 16/64
MIDIenable = WordSelect+CounterDiv ;IRQ is disabled with this value
IRQenable = RxIntEnable+WordSelect+CounterDiv
IntType = IRQmode
.bend
.fi
;=========================== Datel object ==============================
.if (DatelJMS_support!=0) ;DATEL/SIEL/JMS/C-LAB (double-speed devices)
DatelJMS .block
DevName = "DATELJMS"
MIDIcontrol = $de04 ;write-only
MIDIstatus = $de06 ;read-only
MIDI_Tx = $de05 ;write-only
MIDI_Rx = $de07 ;read-only
MIDIspeed= 2
CounterDiv = (MIDIspeed==1) ? 0*bit1+1*bit0 : 1*bit1+0*bit0;div by 16/64
MIDIenable = WordSelect+CounterDiv ;IRQ is disabled with this value
IRQenable = RxIntEnable+WordSelect+CounterDiv
IntType = IRQmode
.bend
.fi
;========================== NameSoft object ============================
.if (NameSoft_support!=0);codebase supported by Gartenzwerg(Frank Buss)
NameSoft .block
DevName = "NAMESOFT"
MIDIcontrol = $de00 ;write-only
MIDIstatus = $de02 ;read-only
MIDI_Tx = $de01 ;write-only
MIDI_Rx = $de03 ;read-only
MIDIspeed= 1
CounterDiv = (MIDIspeed==1) ? 0*bit1+1*bit0 : 1*bit1+0*bit0;div by 16/64
MIDIenable = WordSelect+CounterDiv ;NMI is disabled with this value
IRQenable = RxIntEnable+WordSelect+CounterDiv
IntType = NMImode
.bend
.fi
;========================NameSoft-FB IRQ object =======================
.if (NameSoftIRQ_support!=0) ;NameSoft with FB uning IRQ instead of NMI
NameSoftIRQ .block ;It's essentially the same as Sequential MIDI
DevName = "NAMESIRQ"
MIDIcontrol = $de00 ;write-only
MIDIstatus = $de02 ;read-only
MIDI_Tx = $de01 ;write-only
MIDI_Rx = $de03 ;read-only
MIDIspeed= 1
CounterDiv = (MIDIspeed==1) ? 0*bit1+1*bit0 : 1*bit1+0*bit0;div by 16/64
MIDIenable = WordSelect+CounterDiv ;NMI is disabled with this value
IRQenable = RxIntEnable+WordSelect+CounterDiv
IntType = IRQmode
.bend
.fi
;=========================== Maplin object =============================
.if (Maplin_support!=0) ;Electronics - Maplin magazine (Vice/C64-midi.c)
Maplin .block
DevName = " MAPLIN "
MIDIcontrol = $df00 ;write
MIDIstatus = $df00 ;read
MIDI_Tx = $df01 ;write
MIDI_Rx = $df01 ;read
MIDIspeed= 2
CounterDiv = (MIDIspeed==1) ? 0*bit1+1*bit0 : 1*bit1+0*bit0;div by 16/64
MIDIenable = WordSelect+CounterDiv ;IRQ is disabled with this value
IRQenable = RxIntEnable+WordSelect+CounterDiv
IntType = IRQmode
.bend
.fi
;====================== Moog Song Producer object ======================
.if (MoogSP_support!=0) ;Moog Song Producer
MoogSP .block
DevName = "MOOG SP."
MIDIcontrol = $de00 ;write (U17 "W")
MIDIstatus = $de00 ;read (U17 "W")
MIDI_Tx = $de01 ;write (U17 "W")
MIDI_Rx = $de01 ;read (U17 "W")
;$de02: U18 "X" CR/SDR, $de03: U18 "X" TDR/RDR,
;$de04: U19 "Y" CR/SDR, $de05: U19 "Y" TDR/RDR,
;$de06: U20 "Z" CR/SDR, $de07: U20 "Z" TDR/RDR,
;$de08: Drum Trigger Latch 1 , $de09: Drum Trigger Latch 2
Control_Latch1 = $de0a ;set to $14 after init,set to $1C after disabling
Control_Enable = $1C
Control_Disable = $14
;Control_Latch2 = $de0b
;$de0c, $de0d: FootSwitch inputs
MIDIspeed= 1
CounterDiv = (MIDIspeed==1) ? 0*bit1+1*bit0 : 1*bit1+0*bit0;div by 16/64
MIDIenable = WordSelect+CounterDiv ;IRQ is disabled with this value
IRQenable = RxIntEnable+WordSelect+CounterDiv
IntType = IRQmode
.bend
.fi
;=========================== MSSIAH object =============================
;Unfortunately no tech. info available for MSSIAH's MIDI-input
;DevName= " MSSIAH "
;***********************************************************************
MIDIC64_code_end
.cwarn(*>MaxAddr),"HerMIDI code & data shouldn't be over $d000!"
;===================== MISC. INTERNAL CONSTANTS ========================
MaxAddr=$cfff ;code shouldn't be above this address (uses IO & KERNAL)
banksel=$01
;binary bit-values
bit0=1
bit1=2
bit2=4
bit3=8
bit4=16
bit5=32
bit6=64
bit7=128
selfmod=$00 ;default value of self-modified immediate operands
selfmodA=$1111 ;default value of self-modified absolute address operands
ROMRTI=$ea86 ;the RTI command at the end of $EA31 IRQ routine
;=======================================================================
.bend ;end of 'MIDIC64' block
;===================== General Constants, Specs ========================
MIDI .block ;their adjacent bytes can be of values $00..$7F (bit7 off)
;MIDI-event numbers (called 'status bytes'...2nd Nybble is channel No.)
NoteOff = $80 ;followed by 2 bytes: note-number,velocity
NoteOn = $90 ;followed by 2 bytes: notenumber,velocity(if 0:NoteOff)
AfterTouch = $A0 ;followed by 2 bytes: note-number, strength
CommonCtrl = $B0 ;followed by 2 bytes: CC-number(see below), 7-bit value
PrgChange = $C0 ;followed by 1 byte: patch/program number
ChPressure = $D0 ;followed by 1 byte value of channelpressure/aftertouch
PitchWheel = $E0 ;followed by 2 bytes: value high & low 7 bits
;Some OMNI (all channels) effects:
OMNI_min = $F0 ;all commands above this value are OMNI (no channel)
SysExMessg = $F0 ;many bytes (firm ID, data) can follow, ends with $F7
SongSelect = $F3 ;followed by song-number
SysExOver = $F7 ;end of System-Exclusive message
RealTime_min=$F8 ;1-byte transparent commands above (no 'running status')
TimingClock= $F8 ;Timing Clock. Sent 24/QN when synchronization required
StartSqPlay= $FA ;Play current sequence. (Followed by Timing Clocks.)
ContinueSeq= $FB ;Continue at the point the sequence was Stopped.
StopSeqPlay= $FC ;Stop the current sequence.
Undefined = $FD ;can be used for signaling 'End of Data' if needed
ActiveSens = $FE ;no byte after
CC .block ;preceeded by $Bx, followed by 7-bit value (MSB bit7=0):
BankSelect = $00
ModWheel = $01
BreathCtrl = $02
FootControl= $04
PortamTime = $05
ChanVolume = $07
Balance = $08
Panning = $0a
Expression = $0b
Effect1 = $0c
Effect2 = $0d
GeneralFx1 = $10
GeneralFx2 = $11 ;Expression
;$20..$3f: the LSB for the CC-effects $00..$1f
DamperPedal= $40 ;followed by switch-value: 0..$3f / $40..$7f
Portamento = $41 ;followed by switch-value: 0..$3f / $40..$7f
Sustenuto = $42 ;followed by switch-value: 0..$3f / $40..$7f
SoftPedal = $43 ;followed by switch-value: 0..$3f / $40..$7f
Legato = $44 ;followed by switch-value: 0..$3f / $40..$7f
Hold2 = $45 ;followed by switch-value: 0..$3f / $40..$7f
Resonance = $47 ;resonance/timbre/harmonic intensity
ReleaseTime= $48 ;Sound Controllers: $46..$4f
AttackTime = $49
Brightness = $4a ;cutoff-frequency
DecayTime = $4b
VibratoRate= $4c
VibraDepth = $4d
VibraDelay = $4e ;General Purpose Controllers: $50..$$53
PortamCtrl = $54
ReverbFx = $5b ;Effects: 5b..$5f
TremoloFx = $5c
ChorusFx = $5d
DetuneFx = $5e
PhaserDepth= $5f
AllSoundOff= $78 ;Channel Mode Message followed by value $00
ResetCtrler= $79 ;Channel Mode Message followed by value $00
AllNoteOff = $7b ;Channel Mode Message followed by value $00
.bend
.bend
;-----------------------------------------------------------------------
; Information about the Motorola MC6850 ACIA chip:
;ACIA (Asynchronous Communications Interface Adapter) Registers
;Bit: Control Register: Status Register:
;7 Receive Interrupt Enable Interrupt Request (IRQ)
;6 Transmit Control 2 Parity Error (PE)
;5 Transmit Control 1 Receiver Overrun (OVRN)
;4 Word Select 3 Framing Error (FE)
;3 Word Select 2 Clear to Send (CTS)
;2 Word Select 1 Data Carrier Detect (DCD)
;1 Counter Divide Select 2 Transmit Data Register Empty (TDRE)
;0 Counter Divide Select 1 Receive Data Register Full (RDRF)
;=======================================================================
; vim: sw=4 ts=4 syntax=asm:
On On Wed, Feb 14, 2018 at 3:23 PM, I wrote:
Load "geos128de1571.ext.rom" as cartridge rom and select module type "Custom C128 External ROM", which means "C128 External Function ROM". It should boot GEOS and request for a disk with Desktop.
But on the 1541 Ultimate II(+?) it crashes. The file "geos128de1571.ext2.rom" is just the same, but I disabled switching to 2 Mhz - and you find it working. So clearly this is a 2 Mhz issue - completely unrelated to freezing the C128.
Analyzing the problem I found: Mostly all data is read correct. Just a small percentage is read wrong. And every wrong value is the same (cannot find my note while writing this).
Ok, I just found my note: If a value is read wrong, the high byte of the address is read instead of the content of the ROM.
Edit: Probably the same issue has been observed with other module types since them, e. g. easyflash. If you cannot find the mentioned sample files, I'll mail them to you again.
This is a feature request we discussed in the forum:
Gideon said, that it should be possible to handle standard loading routines via DMA-Load.
For example this means a big speed-up for games which have multiple files but do not use any custom loading routine.
This also also means that D71-images could be supported as long as standard loading routines are used (which is the most common usecase for 1571-disks anyway).
Using an external USB keyboard, pressing left shift, left CTRL, Windows and Left Alt resets the machine.
However it resets to vanilla basic and not cartridge init menu even if a cart is present.
Hey there,
This issue has been around since firmware 1.02. I documented it, but totally forgot to follow up on it in later firmware releases. It concerns using the UltiSID. Today, Dave posted about this issue in the facebook group and it promptly made me remember that I already noticed this quite a long time ago.
I noticed this issue after I was running a programme that produces music. I reset the Ultimate 64, then went into the Ultimate men and not much later I pressed run/stop to go back to the basic C64 screen. The U64 started making a sound like the UltiSID hangs. Resetting the U64 made the sound stop, but entering the Ultimate menu and run/stop to go back to the C64 screen made the hanging sound come back. Using f5 / reset or f5 / reboot in the Ultimate menu did not fix this issue. Only a power cycle fixes this behaviour until I start all over again.
To reproduce this issue do the following:
Now you'll hear a this sound this hanging UltiSID sound.
I don't know what the plan for the easyflash save feature is but for stuff like saving high scores in a game it would be great if only the modified data could be saved in a separate file from the base image.
The following BASIC statement should return the value 23, but the U64 returns the value 223!
POKE 0,0: POKE 1,0: ? PEEK (1)
or in assembler:
lda #0
sta 0 ; set all portbits as inputs
sta 1 ; try to set all portbits to 0
lda 1 ; should be #$17, but on the U64 its #$df (bit 3,6 and 7 should be 0)
Request: make REU 512kb wraparound changeable in menu to fully adressable as it was in the early days when the Ultimate came out.
I know its not the behaviour as "it should" - but would be nice to have for some modern apps anyway. Then everyone could decide for himself how to setup it in the menu.
Currently Ulticopy does not append the well-known 683 error log to D64 files, like WarpCopy and Star Commander do. It is of great value to The Transfer Team to add this feature to Ulticopy.
This feature only works if (after setting the cartridge bin file and shutting down) you boot into 64 mode first, then reset the machine back into 128 mode. Is there any way to avoid these steps?
Obviously low on a priority list for such exotic and unwanted hardware, but am creating a ticket for you incase its compatibility helps improve other things as well.
The cpm disk starts to load, then the machine resets.
Im interested in working on the code for the apps (not FPGA). But Ive never done FPGA development before. Will this build a standard U2+ update file, or more lower level than I currently understand?
It seems that the old bug that allows changing to non-existent directories still exist in the current firmware of the U2+ (3.3 (112)). See picture for an illustration:
This can make people believe correctly changing to a directory while actually the had made a typo and changing to a non-existent directory.
The Final Cartridge III that is included in Firmware 3.2 does not work correctly.
It is not possible to get the blue desktop (like here).
I did try another FC III CRT-file I found somewhere and that works fine.
Tested on my C128 and C64 with the PHI2 value that works without problems for other cartridges (and fpr the other FC III image too).
While the Ultimate file browser adds the unit K after kilobytes, it does not add a B when the unit is bytes. This concerns when browsing both the USB storage file system and inside the disk images.
An example from the file system:
And an example from inside a disk image:
ps: I used the remote menu for the ease of creating screenshots. It looks exact the same in the freeze interface type.
Reproduce:
Enable Dolphin DOS kernal and drive ROM (remember to also enable the 24k RAM and the virtual parallel cable).
Press the menu button and then "F5", insert a new, unformatted floppy disk.
Use "@n:test,41+" to format the disk.
After finishing the format, you always get a read error. :/
Now again press the menu key and "F5" and unmount the disk, without saving.
Next step re-enter the "F5" menu and mount a new unformatted floppy disk and again format it with "@n:test,41+"! Now you get a "OK" after formatting and are able to read the directory.
Using the official KoalaPainter cartridge, it will not boot to the cartridge if the pad is plugged in (either port, although the pad should only be used in port 1). Without the pad plugged in, the cart software works fine. Plugging in after has no effect.
I used Ulticopy for copying a bunch of disks, and can remember that it worked fine with some older firmware.
However, using 3.0 and 3.2 Ulticopy will give me a "Error reading disk..." message after copying two disk sides (=1 disk). I will have to reset the drive, then it will work with the next 2 disk sides.
(Using an C128D, drive in 1541 mode).
If I copy a file with <C=>+ inside a T64-image and paste it outside with <C=>+, then a window "Copying..." appears and do not react anymore.
The same operation with images like D64 / D71 / D81 work correctly.
Attached is the zipped file exolon.t64
C64 games and other programs frozen with Trilogic V3.2(and possibly higher) Expert Cartridge fail to run on the Ultimate 64. After loading the programs normally, the screen crashes and shows plain garbage, doing nothing else. This event also occurs on the current version of the cartridge. Two examples of Public Domain
games used this freezer. One used V3.1 and the other used V3.2. V3.1 works.
Is there anyway to detect ultisid on a Ultimate64/UltimateII+ from assembler in the same way that it can be done with other SIDs?
ARMsid and SwindSID Ultimate allow setting $D41D, $D41E, $D41F with the value "SID"
You can then read the value back from the same registers to determine if a ARMSID or SwindSID Ultimate is installed.
FPGA sid use a simular princip by setting $D419 and D41A with a magic cookie.
You can then read the value back from the $D41e and $D41F to determine if a FPGASID is installed.
Would it be possible to implement this? I would also like for it to be possible to read the SIDtype (6581/8580).
I have written a small program for this.
https://csdb.dk/release/?id=176909
From the FB group, just wanted to add this as a feature request. Ability to load and save different configurations of the settings. And i suppose flag one of them as the default configuration.
An external USB keyboard has multiple additional keys over the native C64 keyboard (most notably the F9 to F12). As I find it somewhat inconvenient to dive in and press the power button hundred times per day, I would like to suggest that the feature reset, trigger menu and cartridge freeze are mapped to these accessible keys.
As written, the built in SID player (U2) does not work here when I have my JiffyDOS active.
Seems that the alternate kernal is loaded at this address:
#define C64_KERNAL_BASE 0x0ECC000
Obviously this is not a C64 address, but likely an address in the FPGA or external RAM, etc. This appears to be an incorrect value for the 128 in 64 mode though. My test machine is a 128DCR, so that could have a play in it as well.
In c64.cc:
void C64::enable_kernal(uint8_t *rom, bool fastreset)
{
if (fastreset && !memcmp((void *) (rom+0x1d6c), (void *) fastresetOrg, sizeof(fastresetOrg)))
memcpy((void *) (rom+0x1d6c), (void *) fastresetPatch, 22);
if (getFpgaCapabilities() & CAPAB_ULTIMATE64) {
memcpy((void *)U64_KERNAL_BASE, rom, 8192); // as simple as that
} else { // the good old way
C64_KERNAL_ENABLE = 1;
uint8_t *src = rom;
uint8_t *dst = (uint8_t *) (C64_KERNAL_BASE + 1);
for (int i = 0; i < 8192; i++) {
*(dst) = *(src++);
dst += 2;
}
}
}
Discovered this by trying to load JiffyDOS 64 kernal. Was also looking to being able to load the C128 kernal as well. Instead of a 8k kernal, it is a 16k kernal and maps to the following:
0000-0FFF C128 editor ROM (C000-CFFF)
1000-1FFF Z80 CP/M ROM BIOS (0000-0FFF)
2000-3FFF C128 KERNAL ROM (E000-FFFF)
The ultimate menu screen is shown when pressing the middle button and the Usb0 or 1 device is listed but the UI and the cartridge buttons stops not react on input so the computer has to be rebooted to work again.
It happens often but not all the time. Pressing the "home" button on the keyboard works. My home is simply the root of either usb0 or usb1.
I have not been able to reproduce the problem if I disable the "enter home directory at startup" option. I've tested with the default u2+ usb stick and the kingston stick I bought with the U2+ in both usb0 and usb1.
So I'm guessing it's some kind of race condition, maybe the device is trying to enter the directory before the files ystem access is properly initialized or something...
Pls see the attached code. It will allow the 64 mode of a 128 to write to the VDC screen. I have started learning the code and want to get involved and though that implementing a copy of the screen to the VDC would be a great addition for 128 users. The code works fine. However, I dont know how I can execute this type of code from within the U2+ environment. Is there any way to do this? See attachment and source code included on the disk.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.