[HN Gopher] Dirty tricks 6502 programmers use (2019)
___________________________________________________________________
Dirty tricks 6502 programmers use (2019)
Author : amichail
Score : 71 points
Date : 2025-04-16 13:58 UTC (3 hours ago)
(HTM) web link (nurpax.github.io)
(TXT) w3m dump (nurpax.github.io)
| pvg wrote:
| Thread some years ago
| https://news.ycombinator.com/item?id=20732867
| vidarh wrote:
| Always fun to see what we wrote years ago...
| dhosek wrote:
| I remember the annoyance a lot of people had with the non-
| sequential layout of text/graphics memory on the Apple ][ (thanks
| to Woz's clever hacks to reduce chip count), but when writing
| assembly code to access screen locations, it turned out that it
| was actually easier to deal with the somewhat weird arrangement
| of bytes than it would have if everything were sequentially
| arranged in memory. Those little 8-byte gaps every three (non-
| consecutive) rows made calculating row starts much simpler.
| devmor wrote:
| I've run into a similar effect when reverse engineering custom
| http packet protocols - the ones that have a unique pattern to
| the data structure are often easier to discern the usefulness
| of at a glance before even extracting the data I'm looking for!
| univacky wrote:
| When Jordan Mechner wrote Karateka for the Apple ][, he used an
| array of pointers to rows. A team member realized that by
| inverting the order of the array, all graphics would appear
| upside down. Broderbund agreed to ship that "upside down"
| version on the backside of the single-sided floppy, so that if
| you booted it upside down it played upside down.
|
| https://www.theverge.com/2021/7/5/22564151/karateka-apple-ii...
|
| https://archive.org/details/wozaday_Karateka_Side_B
| deater wrote:
| haha as someone who has spent a lot of time recently doing
| Apple II graphics coding, both for games, sizecoding, and the
| demoscene, let me tell you that the weird layout in fact is not
| easier to deal with.
|
| You have to waste a lot of space on lookup tables, or else
| complex calculations. And don't get me started on the "screen
| holes" you aren't allowed to write to in the lo-res address
| space making it exciting if you're trying to use modern
| decompression routines to unpack graphics in-place
| flohofwoe wrote:
| The best 8-bitter video memory layout (for pixel data) I have
| seen is in the little known KC85/4:
|
| The display is 320x256 pixels, organized into 40x256 bytes for
| pixels (8 pixels per byte) and another 40x256 bytes for Speccy-
| like color attribute bytes (the color blocks are just 8x1
| instead of 8x8 pixels), the start address for video memory is
| 0x8000 with the pixels and colors in different video bank.
|
| Now the twist: the video memory layout is vertical, e.g.
| writing consecutive bytes in video memory fills vertical pixel
| columns.
|
| This layout is perfect for the Z80 with its 16-bit register
| pairs. To 'compute' a video memory location:
| LD H, 0x80 + column ; column = 0..39 LD L, row
| ; row = 0..255
|
| ...and now you have the address of a pixel- or color-byte in
| HL.
|
| To blit an 8x8 character just load the start of the font pixels
| into DE and do 8x unrolled LDI.
|
| Unfortunately the KC85/4 had a slow CPU clock (at 1.77 MHz only
| half as fast as a Speccy), but it's good enough for stuff like
| this:
|
| https://floooh.github.io/kcide-sample/kc854.html?file=demo.k...
| p0w3n3d wrote:
| Quite surprising for me as a long time Atari 65XE user is that
| those PRG were starting with a basic command. On Atari all binary
| programs were loaded without BASIC in memory. If you forgot to
| disable basic, there was a chance the program wouldn't run or
| would hang. I guess this must have been due to different memory
| layout?
| bluGill wrote:
| C64 always had basic built in. Because it was there you could
| assume it, and further it being there affected how the system
| booted. I'm was never a C64 guy so don't know what the options
| were for someone who didn't want basic.
|
| The original Atari didn't have built in basic (the 2nd
| generation XL and your 3rd generation XE series both did). As
| such Atari programmers could never assume basic, and even when
| you could assume basic you couldn't assume the version, there
| were a few bugs in various versions. (I knew someone with a XL
| who used the earlier version of basic because the bugs in the
| XL version were serious enough to affect his usage).
| vardump wrote:
| Unless you use only cartridges, BASIC ROM is required to load
| anything at all from disk or tape.
|
| Once your program loads you can turn the BASIC ROM off to see
| the RAM underneath.
|
| Commodore MAX Machine was basically a stripped down C64. It
| had just 2 kB RAM and no ROMs at all.
|
| https://www.c64-wiki.com/wiki/Commodore_MAX_Machine
| dspillett wrote:
| IIRC the C64, like the BBC range of 6502-based Micros, had
| their BASIC in ROM and in fact booted to it in REPL mode by
| default. As such it was always in memory as the ROM would
| always be there1. There were certain bits of the address space
| that were not safe to use if the user would drop back into
| BASIC as the ROM used those for its stack & heap and other
| scratch space, but otherwise you could ignore BASIC's existence
| once your machine code was running.
|
| ----
|
| [1] caveat: under usual circumstances, on the Beebs you could
| switch a different bank into the memory space used by the BASIC
| ROM, either another ROM or some "sideways RAM"
| Luc wrote:
| You can do the same bank switching on a C64. Through
| different bits of RAM location $0001 you can switch off the
| BASIC, KERNAL and character ROMs, exposing the RAM in those
| locations.
| gabrielsroka wrote:
| The C64 has a BASIC ROM and a kernal ROM. You can swap out
| the BASIC ROM or both ROMs for RAM using addresses 0 and 1 on
| the 6510.
| RiverCrochet wrote:
| The C64 always booted to BASIC, specifically CBM BASIC 2.0.
| There wasn't a provision for automatic booting from disk until
| at least the C128.
|
| LOAD "*",8,1 was the command to load the first file off of your
| attached 1541 (if you were lucky enough to have multiple 1541s,
| your first one would be device 8 and you'd have had to set the
| device number on others to 9 or higher). Anyone who had and
| played a lot of games on the C64 back in the day has this
| command etched in their permanent memory.
|
| There was the convenient-looking RUN/STOP key (yes it is
| confusing, it's STOP without SHIFT, and RUN with SHIFT held
| down) but the RUN key would only auto-load from device 1 which
| was the cassette. Made sense in 1982 when the machine was
| released because disk drives were about $500 in 1982 dollars,
| the same price as the system itself.
|
| BASIC 2.0 had no "BLOAD" or "BRUN" to directly load and/or run
| a binary executable. The underlying Kernal could do this, but
| BASIC left a LOT of functionality on the C64 unexposed (such as
| - all the sprites and graphics modes). So the standard was to
| release programs that were in a form that would look like a
| BASIC program.
|
| So C64 BASIC doesn't have a BLOAD command but ... it kinda did
| in a janky way. The ,1 in LOAD"*",8,1 means to "not relocate
| the file" - and any PRG file on a 1541 disk will have the
| intended address of the "program" as its first two bytes. If
| the ,1 is present, BASIC will tell the Kernal to load the file
| at the address it specifies. (There was no SAVE"xxx",8,1). Some
| software would load to an address that would overwrite the
| BASIC main loop vectors and immediately start without having to
| type RUN afterward. Without the ,1 BASIC will load it into the
| BASIC program text space at 2048.
|
| Much other software was a hacked BASIC program that had one
| command, something like 10 SYS 2057 or similar, and then 6502
| code right after the necessary codes that told BASIC the end of
| program text was reached. BASIC program text started at memory
| location 2048, right after the 1K of screen RAM at 1024. SYS is
| a command that simply jumps to a machine language program - and
| in this case, it's jumping to the binary tacked on to the end
| of the small BASIC program, which would be the game or at least
| a booting program for the game.
|
| Programs like this had the actual address in the PRG matching
| what BASIC would want, so LOAD "*",8 or LOAD"*",8,1 typically
| made no difference unless the game was that auto-RUNing type.
|
| The C64 had 4K of RAM not used for anything else at 49152. It
| was common for utilities to live there, so you'd load those in
| with a LOAD"something",8,1 and then SYS 49152 to start them.
| masto wrote:
| The C64 starts up straight into BASIC from ROM. Unlike some
| other contemporary computers, it doesn't attempt to boot from
| any external devices (except the cartridge port). There isn't
| really a DOS in the usual sense. Apart from simple support for
| loading and saving programs, and a very basic channel I/O
| facility, everything else is handled by the firmware in the
| disk drive, which has its own 6502 and operating system.
|
| For example, there's no command for getting a directory
| listing. You type `LOAD "$",8` (8 being the disk drive), and
| the drive pretends there's a BASIC program called `$` that
| happens to contain a directory listing you can then look at
| with `LIST`. (https://en.wikipedia.org/wiki/Commodore_DOS#/medi
| a/File:Comm...)
|
| By default, LOAD loads tokenized BASIC programs, but if you add
| an extra `,1` to the command, the file can contain arbitrary
| data starting at any location in memory. You could use this to
| load a machine language program and then run it with `SYS
| <location>`. Clever programmers figured out they could skip
| this step by having their file overwrite a vector that gets
| called after the load completes and jump right into their code,
| resulting in every Commodore kid having being able to type
| `LOAD"*",8,1` on autopilot.
|
| I got distracted by other trivia (I grew up with this computer
| and it was hugely influential and I will adore it forever) from
| getting to the actual point: The C64 uses a variant of the
| 6502, the 6510. It has a special register for swapping out any
| combination of the three ROMs (BASIC, KERNAL (sic), and the
| character ROM) plus I/O registers that overlay portions of the
| 64 address space. If your code doesn't use those, you can
| access the RAM they are hiding by turning them off.
| p0w3n3d wrote:
| On my ATARI there was no DOS too. When you start the 65XE you
| can hold (iirc) START to start loading an application from
| the cassette recorder, but it was recommended to hold both
| (again iirc) START and OPTION to bypass BASIC, because BASIC
| interpreter being held in the memory, somehow interfered with
| bigger games (I think this was due to memory, but I'd like to
| learn from someone who know). I myself got into this trouble
| sometimes. Also you could have a CARTDRIGE with DOS-like
| Turbo management which allowed to scan cassette for given
| filename with binary application, but no one used this
| because it would take crazy long. I never had chance to use
| floppy disk, but I think it was behaving in a similar way
| (you had to have a floppy with DOS and hold START when
| powering the computer to load it), but at that time the FDD
| drives for atari were horryfyingly expensive (they had the
| same CPU 6502, and even there were some demoes which used
| this CPU as a coprocessor), so I stayed with a cassete reader
| with TURBO.
|
| Of course games were also sold on CARTDRIGEs and this was the
| fastest way to play, but it wasn't popular in my country.
| pwg wrote:
| On the Atari's you could also run 6502 binaries from inside
| Atari BASIC. The Atari ROM OS explicitly reserved page 6 of the
| memory map for "user use" and Atari Basic followed suit. There
| were (IIRC) also a tiny number of page 0 bytes reserved for
| 'user use' as well.
|
| So, as long as your entire binary fit into 256 bytes, you could
| run it from inside BASIC. In fact, you could even store it as a
| BASIC program, the BASIC just needed to "POKE" the binary into
| page 6, and then you could jump to it.
|
| To do anything larger than 256 bytes required you to dig into
| the inner workings of where BASIC stored code itself and avoid
| overwriting any of BASIC's data, or having it overwrite any of
| your code. Not impossible to do, but did require a lot of
| undocumented (or not so well documented) work.
| delduca wrote:
| I wrote a 6502 emulator in Lua
|
| https://github.com/willtobyte/MOS6502
___________________________________________________________________
(page generated 2025-04-16 17:00 UTC)