GithubHelp home page GithubHelp logo

joeldipops / gbz80-pseudoops Goto Github PK

View Code? Open in Web Editor NEW
8.0 1.0 1.0 84 KB

Set of rgbasm macros and constants to facilitate readability for modern programmers

License: MIT License

Assembly 99.50% Makefile 0.50%
rgbds game-boy gameboy game-boy-development gbz80

gbz80-pseudoops's Introduction

gbz80-pseudoOps

Set of rgbasm macros and constants to facilitate readability for modern programmers.

I've only just started using ASM, but like most programmers born in the 90s I've gotten used to a) Doing things in one step instead of two or three and b) camelCase.
So this is my attempt to simplify the writing and most relevantly the reading of asm code without comprimising the control over optimisation required to run gameboy software as well as it needs to run.

This is a work in progress, so more pseudo-ops will be added as I come across a case for them in the software I write.

Usage

The ops can be included with INCLUDE "ops.inc"

There's also a list of hardware memory locations, with names like BackgroundScrollX that you may prefer to the traditional gbhw.inc names such as rSCY. That's in INCLUDE "addresses.inc"

As well as some random utility macros you may find a use for.

You can include everything with INCLUDE "gbz80-pseudoOps.inc. It's all macros so won't take up any cart space or cycles, but may increase compliation time in larger projects.

Acknowledgements

Thanks to DonaldHays for writing the 'jump if greather than or equal to' style ops. ISSOtm for suggesting various improvements and submitting pull requests.

Legend

List of abbreviations, as used by rgbasm in https://rednex.github.io/rgbds/gbz80.7.html

Symbol Def
r8 Any of the 8-bit registers (A, B, C, D, E, H, L).
r16 Any of the general-purpose 16-bit registers (BC, DE, HL).
n8 8-bit integer constant.
n16 16-bit integer constant.
e8 8-bit offset (-128 to 127).
u3 3-bit unsigned integer constant (0 to 7).

The Ops

Unless otherwise specified, all ops will overwrite A, and have no other side-effects

Don't take these sizes/timings as gospel - I've added them up by hand, but haven't done any tests to make sure they are exact.

mult

mult r8, ?r16

  • Multiplies A with register r8. Result in HL.
  • Optionally, specify BC or DE to be affected and save 8 cycles, 2 bytes
  • Cycles: Depends on value of operands.
  • Bytes: 18 if r16 supplied
  • Flags:
    • Z: 1
    • N: 1
    • H: 0
    • C: 0

mult n8, ?r16

  • Multiplies A with n8. Result in HL.
  • Optionally, specify BC or DE to be affected and save 8 cycles, 2 bytes
  • Cycles: Depends on value of operands.
  • Bytes: 20 if r16 supplied
  • Flags: As above

mult [n16], ?r16

  • Multiplies A with value at [n16]. Result in HL.
  • Optionally, specify BC or DE to be affected and save 8 cycles, 2 bytes
  • Cycles: Depends on value of operands.
  • Bytes: 22 if r16 supplied
  • Flags: As above

mult [r16], ?r16

  • Multiplies A with value at address in [r16]. Result in HL.
  • Optionally, specify BC or DE to be affected and save 8 cycles, 2 bytes
  • Cycles: Depends on value of operands.
  • Bytes: 21 if r16 supplied
  • Flags: As above

ldAny

Will perform the fastest/smallest 8 bit ld it can. Prepending an address or label with # will cause the ldh pnemonic to be used when loading to/from that address. You can change this token to whatever you want by changing LDH_TOKEN in config.inc Be careful with EQUS defines. ldAny doesn't know doesn't know when it can {dereference} them to something it can process, so you'll have to do it yourself, eg ldAny LOW({PARAM_2\@}), {PARAM_2\@}.

ldAny A, 0

  • Assembles to xor A, A

ldAny [r16], 0 ldAny #[$ff00 + n8], 0

  • Cycles: 4
  • Bytes: 3
  • Flags
    • Z: 0
    • N: 0
    • H: 0
    • C: 0

ldAny [n16], 0

  • Cycles: 5
  • Bytes: 4
  • Flags: As above

ldAny #[$ff00 + n8], r8 ldAny r8, #[$ff00 + n8]

  • Cycles: 4
  • Bytes: 3
  • Flags: None

ldAny #[$ff00 + n8], [r16] ldAny [r16], #[$ff00 + n8]

  • Cycles: 5
  • Bytes: 3
  • Flags: None

ldAny #[$ff00 + n8], #[$ff00 + n8]

  • Cycles: 6
  • Bytes: 4
  • Flags: None

ldAny #[$ff00 + n8], [n16] ldAny [n16], #[$ff00 + n8]

  • Cycles: 7
  • Bytes: 5
  • Flags: None

ldAny #[$ff00 + n8], n8

  • Cycles: 5
  • Bytes: 4
  • Flags: None

ldAny r8, [n16] ldAny [n16], r8

  • Store the value at address n16 into register r8.
  • Cycles: 5
  • Bytes: 4
  • Flags: None

ldAny r8, [r16] ldAny [r16], r8

  • Store the value pointed to by register r16 into register r8
  • Cycles: 3
  • Bytes: 2
  • Flags: None

ldAny [r16], [n16] ldAny [n16], [r16]

  • Store the value at address n16 into address pointed to by register r16
  • Cycles: 6
  • Bytes: 4
  • Flags: None

ldAny [r16], [r16]

  • Store the value pointed to by register r16 in to address pointed to by other register r16
  • Cycles: 4
  • Bytes: 2
  • Flags: None

ldAny [n16], [n16]

  • Store the value at address n16 into other address n16
  • Cycles: 8
  • Bytes: 6
  • Flags: None

ldAny [n16], n8

  • Store value n8 to address n16
  • Cycles: 6
  • Bytes: 5
  • Flags: None

ld16

ld16 r16, r16

  • Stores the value of one 16 bit register in to another.
  • eg. ld16 HL, BC
  • Cycles: 2
  • Bytes: 2
  • Flags: None

ld16 r16, [n16]

  • Stores the 16bit value at address n16 and following byte in to register r16
  • eg. ld16 HL, $c123
  • Cycles: 10
  • Bytes: 8
  • Flags: None

ld16 [n16], r16

  • Stores the value in r16 to address n16 and following address
  • eg. ld16 $c123, HL
  • Cycles: 10
  • Bytes: 8
  • Flags: None

ld16 [n16], [n16]

  • Stores the 16bit value at one address n16 (and next address) in to another address n16 and next address.
  • eg. ld16 $d321, $c123
  • Cycles: 10
  • Bytes: 8
  • Flags: None

sub16

sub16 r16, r16

  • Subtracts the value of 1 16bit register from another and stores the result into the first register.
  • eg. sub16 HL, BC
  • Cycles: 6
  • Bytes: 6
  • Flags:
    • Z: Set if value in high byte is 0, reset otherwise
    • N: 1
    • H: Reset if borrow from bit 11, set otherwise.
    • C: Set if first r16 < second r16, reset otherwise.

ldiAny/lddAny

ldiAny r8, [HL] lddAny r8, [HL]

  • Store value at address pointed to by HL into register r8 then increments/decrements HL
  • Cycles: 3
  • Bytes: 2
  • Flags: None

ldiAny [r16], [HL] lddAny [r16], [HL]

  • Store value at address pointed to by HL into address pointed to by r16 then increments/decrements HL
  • Cycles: 4
  • Bytes: 2
  • Flags: None

ldiAny [n16], [HL] lddAny [n16], [HL]

  • Store value at address pointed to by HL into address n16 then increments/decrements HL
  • Cycles: 6
  • Bytes: 4
  • Flags: None

ldiAny [HL], r8 lddAny [HL], r8

  • Storevalue of r8 into address pointed to by HL then increments/decrements HL
  • Cycles: 3
  • Bytes: 2
  • Flags: None

ldiAny [HL], [r16] lddAny [HL], [r16]

  • Store value at address pointed to by n16 in to address pointed to by HL then increments/decrements HL
  • Cycles: 4
  • Bytes: 2
  • Flags: None

ldiAny [HL], [n16] lddAny [HL], [n16]

  • Store value at address n16 in to address pointed to by HL then increments/decrements HL
  • Cycles: 6
  • Bytes: 4
  • Flags: None

orAny

orAny r8, r8

  • Bitwise OR between the values in two registers r8. Result in A
  • Cycles: 2
  • Bytes: 2
  • Flags:
    • Z: Set if result is 0, reset otherwise
    • N: 0
    • H: 0
    • C: 0

orAny r8, n8

  • Bitwise or between the value in r8 and n8. Result in A
  • Cycles: 4
  • Bytes: 4
  • Flags:
    • Z: Set if result is 0, reset otherwise
    • N: 0
    • H: 0
    • C: 0

orAny r8, [HL]

  • Bitwise OR between the value in r8 and the value at address pointed to by HL. Result in A
  • Cycles: 3
  • Bytes: 2
  • Flags:
    • Z: Set if result is 0, reset otherwise
    • N: 0
    • H: 0
    • C: 0

orAny [r16], r8

  • Bitwise OR between the value at address pointed to by r16 and the value in r8. Result in A
  • Cycles: 3
  • Bytes: 2
  • Flags:
    • Z: Set if result is 0, reset otherwise
    • N: 0
    • H: 0
    • C: 0

orAny [r16], n8

  • Bitwise OR between the value at address pointed to by r16 and n8. Result in A
  • Cycles: 4
  • Bytes: 3
  • Flags:
    • Z: Set if result is 0, reset otherwise
    • N: 0
    • H: 0
    • C: 0

orAny [r16], [HL]

  • Bitwise OR between the value at address pointed to by r16 and the value at address pointed to by HL. Result in A
  • Cycles: 4
  • Bytes: 2
  • Flags:
    • Z: Set if result is 0, reset otherwise
    • N: 0
    • H: 0
    • C: 0

orAny [n16], r8

  • Bitwise OR between the value at address n16 and the value of r8. Result in A
  • Cycles: 5
  • Bytes: 4
  • Flags:
    • Z: Set if result is 0, reset otherwise
    • N: 0
    • H: 0
    • C: 0

orAny [n16], n8

  • Bitwise OR between the value at address n16 and n8. Result in A
  • Cycles: 6
  • Bytes: 5
  • Flags:
    • Z: Set if result is 0, reset otherwise
    • N: 0
    • H: 0
    • C: 0

orAny [n16], [HL]

  • Bitwise OR between the value at address n16 and the value at address pointed to by HL. Result in A
  • Cycles: 6
  • Bytes: 4
  • Flags:
    • Z: Set if result is 0, reset otherwise
    • N: 0
    • H: 0
    • C: 0

andAny

andAny r8, r8

  • Bitwise AND between two registers r8. Result in A
  • Cycles: 2
  • Bytes: 2
  • Flags:
    • Z: Set if result is 0, reset otherwise
    • N: 0
    • H: 1
    • C: 0

andAny r8, n8

  • Bitwise AND between the value in r8 and n8. Result in A
  • Cycles: 4
  • Bytes: 4
  • Flags:
    • Z: Set if result is 0, reset otherwise
    • N: 0
    • H: 1
    • C: 0

andAny r8, [HL]

  • Bitwise AND between the value in r8 and the value at address pointed to by HL. Result in A
  • Cycles: 3
  • Bytes: 2
  • Flags:
    • Z: Set if result is 0, reset otherwise
    • N: 0
    • H: 1
    • C: 0

andAny [r16], r8

  • Bitwise AND between the value at address pointed to by r16 and the value in r8. Result in A
  • Cycles: 3
  • Bytes: 2
  • Flags:
    • Z: Set if result is 0, reset otherwise
    • N: 0
    • H: 1
    • C: 0

andAny [r16], n8

  • Bitwise AND between the value at address pointed to by r16 and n8. Result in A
  • Cycles: 4
  • Bytes: 3
  • Flags:
    • Z: Set if result is 0, reset otherwise
    • N: 0
    • H: 1
    • C: 0

andAny [r16], [HL]

  • Bitwise AND between the value at address pointed to by r16 and the value at address pointed to by HL. Result in A
  • Cycles: 4
  • Bytes: 2
  • Flags:
    • Z: Set if result is 0, reset otherwise
    • N: 0
    • H: 1
    • C: 0

andAny [n16], r8

  • Bitwise AND between the value at address n16 and the value in r8. Result in A
  • Cycles: 5
  • Bytes: 4
  • Flags:
    • Z: Set if result is 0, reset otherwise
    • N: 0
    • H: 1
    • C: 0

andAny [n16], n8

  • Bitwise AND between the value at address pointed to by r16 and n8. Result in A
  • Cycles: 6
  • Bytes: 5
  • Flags:
    • Z: Set if result is 0, reset otherwise
    • N: 0
    • H: 1
    • C: 0

andAny [n16], [HL]

  • Bitwise AND between the value at address pointed to by r16 and the value at address pointed to by HL. Result in A
  • Cycles: 6
  • Bytes: 4
  • Flags:
    • Z: Set if result is 0, reset otherwise
    • N: 0
    • H: 1
    • C: 0

xorAny

xorAny r8, r8

  • Bitwise XOR between the value of two registers r8. Result in A
  • Cycles: 2
  • Bytes: 2
  • Flags:
    • Z: Set if result is 0, reset otherwise
    • N: 0
    • H: 0
    • C: 0

xorAny r8, n8

  • Bitwise XOR between the value of r8 and n8. Result in A.
  • Cycles: 4
  • Bytes: 4
  • Flags:
    • Z: Set if result is 0, reset otherwise
    • N: 0
    • H: 0
    • C: 0

xorAny r8, [HL]

  • Bitwise XOR between the value of r8 and the value at address pointed to by HL. Result in A
  • Cycles: 3
  • Bytes: 2
  • Flags:
    • Z: Set if result is 0, reset otherwise
    • N: 0
    • H: 0
    • C: 0

xorAny [r16], r8

  • Bitwise XOR between the value at address pointed to by r16 and the value in r8. Result in A
  • Cycles: 3
  • Bytes: 2
  • Flags:
    • Z: Set if result is 0, reset otherwise
    • N: 0
    • H: 0
    • C: 0

xorAny [r16], n8

  • Bitwise XOR between the value at address pointed to by r16 and n8. Result in A
  • Cycles: 4
  • Bytes: 3
  • Flags:
    • Z: Set if result is 0, reset otherwise
    • N: 0
    • H: 0
    • C: 0

xorAny [r16], [HL]

  • Bitwise XOR between the value at address pointed to by r16 and the value at address pointed to be HL. Result in A
  • Cycles: 4
  • Bytes: 2
  • Flags:
    • Z: Set if result is 0, reset otherwise
    • N: 0
    • H: 0
    • C: 0

xorAny [n16], r8

  • Bitwise XOR between the value at address n16 and the value of r8. Result in A
  • Cycles: 5
  • Bytes: 4
  • Flags:
    • Z: Set if result is 0, reset otherwise
    • N: 0
    • H: 0
    • C: 0

xorAny [n16], n8

  • Bitwise XOR between the value at address n16 and n8. Result in A
  • Cycles: 6
  • Bytes: 5
  • Flags:
    • Z: Set if result is 0, reset otherwise
    • N: 0
    • H: 0
    • C: 0

xorAny [n16], [HL]

  • Bitwise XOR between the value at address n16 and the value at address pointed to by HL. Result in A
  • Cycles: 6
  • Bytes: 4
  • Flags:
    • Z: Set if result is 0, reset otherwise
    • N: 0
    • H: 0
    • C: 0

resAny

resAny u3, [n16]

  • Resets bit u3 of value at address n16
  • Cycles: 10
  • Bytes: 8
  • Flags: None

resAny u3, [r16]

  • Resets bit u3 of value at address pointed to by r16
  • Cycles: 6
  • Bytes: 4
  • Flags: None

cpAny

cpAny r8, n8

  • Subtract the n8 from the value in r8 and set flags accordingly, without storing the result.
  • Cycles: 4
  • Bytes: 4
  • Flags:
    • Z: Set if result is 0, reset otherwise
    • N: 1
    • H: Reset if borrow from bit 4, set otherwise.
    • C: Set if n8 > r8, reset otherwise

cpAny r8, r8

  • Subtract the value in one register r8 from another register r8 and set flags accordingly, without storing the result.
  • Cycles: 3
  • Bytes: 3
  • Flags:
    • Z: Set if result is 0, reset otherwise
    • N: 1
    • H: Reset if borrow from bit 4, set otherwise.
    • C: Set if second r8 > than first r8, reset otherwise

cpAny r8, [HL]

  • Subtract the value at address pointed to by HL from value of r8 and set flags accordingly, without storing the result.
  • Cycles: 4
  • Bytes: 3
  • Flags:
    • Z: Set if result is 0, reset otherwise
    • N: 1
    • H: Reset if borrow from bit 4, set otherwise.
    • C: Set if value at [HL] > r8, reset otherwise

cpAny [r16], n8

  • Subtract n8 from value at address pointed to by r16 and set flags accordingly, without storing the result.
  • Cycles: 4
  • Bytes: 3* Flags:
    • Z: Set if result is 0, reset otherwise
    • N: 1
    • H: Reset if borrow from bit 4, set otherwise.
    • C: Set if n8 > value at [r16], reset otherwise

cpAny [r16], r8

  • Subtract value in r8 from value at address pointed to by r16 and set flags accordinly, without storing the result.
  • Cycles: 3
  • Bytes: 2
  • Flags:
    • Z: Set if result is 0, reset otherwise.
    • N: 1
    • H: Reset if borrow from bit 4, set otherwise.
    • C: Set if r8 > value at [r16], reset otherwise

cpAny [r16], [HL]

  • Subtract value at address pointed to by HL from value at address pointed to by r16 and set flags accordinly, without storing the result.
  • Cycles: 4
  • Bytes: 2
  • Flags:
    • Z: Set if result is 0.
    • N: 1
    • H: Reset if borrow from bit 4, set otherwise.
    • C: Set if [HL] > [r16], reset otherwise

cpAny [n16], n8

  • Subtract n8 from value at address n16 and set flags accordinly without storing the result.
  • Cycles: 6
  • Bytes: 5
  • Flags:
    • Z: Set if result is 0, reset otherwise.
    • N: 1
    • H: Reset if borrow from bit 4, set otherwise.
    • C: Set if n8 > [n16], reset otherwise.

cpAny [n16], r8

  • Subtract value of r8 from value at address n16 and set flags accordinly without storing the result.
  • Cycles: 5
  • Bytes: 4
  • Flags:
    • Z: Set if result is 0, reset otherwise.
    • N: 1
    • H: Reset if borrow from bit 4, set otherwise.
    • C: Set if r8 > [n16], reset otherwise.

cpAny [n16], [HL]

  • Subtract value of address pointed to by HL from value at address n16 and set flags accordinly, without storing the result.
  • Cycles: 6
  • Bytes: 4
  • Flags:
    • Z: Set if result is 0, reset otherwise.
    • N: 1
    • H: Reset if borrow from bit 4, set otherwise.
    • C: Set if [HL] > [r16], reset othwerwise.

incAny

incAny [n16]

  • Increment value in address at n16 by 1
  • Cycles: 9
  • Bytes: 7
  • Flags:
    • Z: Set if result is 0, reset otherwise
    • N: 0
    • H: Set if overflow from bit 3
    • C: Not affected

incAny [r16]

  • Increment value at address pointed to by r16 by 1
  • Cycles: 5
  • Bytes: 3
  • Flags:
    • Z: Set if result is 0, reset otherwise
    • N: 0
    • H: Set if overflow from bit 3
    • C: Not affected

decAny

decAny [n16]

  • Decrement the value at address n16 by 1
  • Cycles: 9
  • Bytes: 7
  • Flags:
    • Z: Set if result is 0, reset otherwise
    • N: 1
    • H: Reset if borrow from bit 4, set otherwise
    • C: Not affected

decAny [r16]

  • Cycles: 5
  • Bytes: 3
  • Flags:
    • Z: Set if result is 0, reset otherwise
    • N: 1
    • H: Reset if borrow from bit 4, set otherwise
    • C: Not affected

gbz80-pseudoops's People

Contributors

issotm avatar joeldipops avatar jroberts-shortcuts avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

Forkers

gb-archive

gbz80-pseudoops's Issues

ldAny bugged if params include macro-variables eg. PARAM_1\@

As well as things like HIGH($4321).

I realised that I've over-complicated ldAny by checking for r8, n8 or [HL], and then realising I'd also need to check for LOW(r16), HIGH(r16) and more.

It should be easier to check for any square brackets instead.

There might still be an issue when passing certain strings baked in to macro-vars, but will be a cleaner anyway.

Jump pseudo instructions that describe conditions better?

This is a really interesting project you have, that really adds a lot of convenient value in a really straightforward, un-intrusive way. I think it's pretty common for developers to create macros for things that would make sense to be instructions, but aren't. A library that provides many of them all at once makes a lot of sense.

A collection of like-minded macros I wrote before but haven't gotten around to publishing involved making jumps clearer. They add pseudo-instructions for jr, jp, call, and ret for when the previous operation (a sub or a cp) produced a "less than", "greater than", "less than or equal", "greater than or equal", "equal", or "not equal" condition.

I feel like instructions of that sort might make sense for this library. I've attached my previous code. If you think the idea is appropriate for your library, feel free to use it to any extent you wish, harvesting directly, or just inspiring your own macros developed to your particular style and standard.

I will warn that while I'm pretty sure they work correctly, they are a year or two old, I never used them in a real project, I don't remember how well I tested them, and so any or all of them may well be implemented incorrectly :D

https://gist.github.com/DonaldHays/a2cdddba571a20d73e9b5f6550695cf3

Lack of `jr` macros

jr is used much, much more than jp, yet only jp has macros defined for it.

Use quotes to make nicer macros

After looking at the src for https://github.com/ISSOtm/rgbds-structs I think I've discovered that you can use quotes to test what's passed in eg
IF ("\1" == "A")

This would mean I could make the ops I'd dreamed of such as ld16 BC, HL instead of ld16 B,C, H,L

In fact I could improve my macros so much by cutting out useless cycles depending on the params

eg. ldAny A,A

ldAny: macro
IF ("\2" == "A")
ld [\1], \2
ELSE
ld A, \2
ld [\1], A
ENDC
endm

Really hope it works the way I think...

Add some common utils as well. Here's a potential one

SPRITE_SIZE EQU 4

; Don't think this is possible, but worth a shot.
setOAMStage: macro
OAMStage SET \1
endm

;;;
;
; @param \1 Sprite number
; @param \2 X position
; @param \3 Y position
; @param \4 Pointer to image tile
; @param \5 Flags
; @param \6 preserve HL - if 0, HL will be affected, if 1, HL will be unchanged.
;;;
updateSprite: macro
IF (\7 == 1)
push HL
ENDC

ld HL, OAMStage + (\1 * SPRITE_SIZE)
ldi [HL], \2
ldi [HL], \3
ldi [HL], \4
ldi [HL], \5

IF (\6 == 1)
    pop HL
ENDC

endm

updateSprite 3, OAMStage, 32, 32 CursorFrame1, (HAS_PRIORITY | USE_PALETTE_0), 0

`orAny [hl], [hl]` has unexpected behavior

This line makes orAny [hl], [hl] only read from memory once, which is not expected behavior.
This could be useful for reading STAT, for example, or acknowledging by polling memory (some mappers, including custom, work this way)

mult op questionable performance

Try to improve mult op by using example here: http://wikiti.brandonw.net/index.php?title=Z80_Routines:Math:Multiplication

originally here: #8

'Now constant time, and uses less regs'
eg.

;;;
; mult r16, r8
; Multiples an 8-bit number (in LOW(\1)) with H, result in HL
; @param \2 A temporary register. Make SURE it's not one of H, L, HIGH(\1), or LOW(\1).
; @return HL The result
; @return HIGH(\1) 0
; @return \2 0
; @return ZF Set
; @destroy CF
;;;
mult: macro
ld L, 0
ld HIGH(\2), L
ld \2, 7

; Optimized first iteration
sla H
jr NC, .loop\@
ld L, LOW(\2)

.loop@
add HL, HL
jr NC, .noAdd@
add HL, DE
.noAdd
dec \2
jr NZ, .loop@
endm

Documentation out of date.

Both doc comments and readme.md are missing some instructions or have incorrect cycles/bytes/flags for certain cases.

ldh never used

Macros loading from memory (addAny, for example) do not use ldh when effective/possible.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.