santa pazienza. senza tornare indietro addirittura alle schede perforate, "bastava" un programmatore di eeprom (magari autocostruito!) e poi un manuale del processore per cui si intendeva scrivere il codice, e poi pazienza: inserire un codice dopo l'altro... (non proprio in binario... si poteva benissimo avere un tastierino numerico per inserire cifre direttamente in decimale o esadecimale... una comodità);
oggi i programmotri di eprom si interfacciano a un computer in senso moderno, e dunque si può "caricare" sulla eprom di tutto con poco sforzo.
ma se ci tieni a sperimentare la fatica certosina con equipaggiamenti moderni, puoi provare il seguente percorso:
a) procurati un buon manuale completo di opcode per il processore che vuoi usare (diciamo intel x86)
b) scrivi il tuo codice su carta usando il linguaggio assembly
c) sempre con carta e penna, converti ogni istruzione nel/nei byte/s corrispondenti, per comodità puoi scriverli in esadecimale...; ora hai una lunga sequenza di byte... e naturalmente questa è la parte critica
d) ora devi inserire quei byte per memorizzarli da qualche parte...; qui puoi inventarti una applicazione (magari scritta in un linguaggio a più alto livello:D) che ti permette di inserire da un tastierino grafico delle cifre; o peggio... una applicazione che simula la perforazione di schede, bit per bit (e quindi hai solo due "tasti", più almeno un altro "gestionale" per dire che hai finito)... in quest'ultimo caso, invece che averli scritti in esadecimale, potevi scriverli direttamente in binario...)... una volta che hai disposizione questa applicazione ad hoc, pazientemente inserisci i byte... questa applicazione li salverà su un file, che puoi intenderla anche come una rappresentazione di comodo di una scheda perforata, se hai "simulato" una scheda perforata [per inciso, ci sono schede perforate molto più evolute, che permettevano di inserire invece che singoli bit, direttamente qualcosa di più significativo; per esempio un buco in una ceta posizione poteva essere la lettera A, per dire... le schede sono solo un metodo di input, quello che può essere inserito è arbitrario e naturalmente dipendente dall'hw del lettore)
e) ora che hai la tua "scheda" o affine memorizata in un file, ... dovresti eseguire il codice... ma non puoi farlo così, immediatamente. allora o scrivi (un'altra) applicazione ad hoc il cui solo scopo è caricare in memoria il codice ed eseguirlo, o il "simulatore" di inserimento di cui al punto precedente non ha scritto nessun file, ma solo "byte" in memoria, sicché fornirà un altro "bottone" per dire "esegui" (e quello che succederà dipende dal tuo codice... naturalmente devi aver tenuto in considerazione il fatto di essere eseguito su un SO moderno... o devi fornire un emulatore di qualche altra cosa)... oppure, ti studi i formati degli eseguibili (PE su windows, ELF su molti altri sistemi, ecc.) e incorpori il tuo codice lì dentro.
il che è molto complicato, ma non impossibile. e inoltre così facendo puoi scrivere in questo modo primitivo una "vera" applicazione per il SO in uso, senza limiti, che invece hai se scrivi il codice così nudo (per esempio, non puoi usare le API del SO perché il binding è dinamico e fatto dal loader del sistema op. usando delle info memorizzate nel file eseguibile, dunque per un intel x86 una "banale"
call CreateWindowEx
non la puoi usare, perché non sai l'indirizzo "vero" della CreateWindowEx; normalmente, in un eseguibile il simbolo è scritto in chiaro (come "testo") e il loader risolve il riferimento sostituendo l'indirizzo opportuno nel codice, che prima di tale operazione contiene un indirizzo fittizio (per esempio, 0))
...