Tag Archives: C64

Writing C64 machinecode using Linux With Visual Studio, Kickass and C64Debugger

While still having a love-hate relationship with Visual Studio (I’m a Vim guy), here is my C64 coding setup. (for now)

Needed:
Vice (C64 emulator (and more))
C64 Debugger (embeds above in an awesome debugger)
Visual Studio
Kickass C64 assembler (you need java for this)
(http://theweb.dk/KickAssembler/Main.html)

Visual Studio click extensions and add kickass by Captain Jinx

https://sourceforge.net/projects/c64-debugger/
This is Commodore 64, Atari XL/XE and NES code and memory debugger that works in real time. It is quick prototyping tool where you can play with Commodore 64 machine and its internals.

I’ve got mostly installed in /data
Change accordingly

Create new file, press ctrl-shift-p and invoke kickass debug!

JiffyDos notes (work in progress)

JiffyDOS is an enhanced DOS for the C64. The software is programmed onto ROM chips that replace the Kernal ROM chip on the motherboard and the DOS ROM chip in the disk drive. JiffyDOS is intended to provide greater speed, commands and convenience than on stock systems.

The 1541 drive is a computer on its own, using a 6502 and VIA chips.
(See other pages) (C64 uses a 6510, that is the same slightly modified version of the 6502)
A cool example of the drive being an OS/computer on its own:
https://www.youtube.com/watch?v=zprSxCMlECA

Some notes:

  • I want to use a larger rom and using the higher address lines as kernal selector. Address line A13 and A14 can be used as selector
  • There is a schematic out there using runstop at boottime to do de selection of the rom part

Did I misspell kernel? NO
(Below from Wikipedia)

The KERNAL was known as kernel inside of Commodore since the PET days, but in 1980 Robert Russell misspelled the word as kernal in his notebooks. When Commodore technical writers Neil Harris and Andy Finkel collected Russell’s notes and used them as the basis for the VIC-20 programmer’s manual, the misspelling followed them along and stuck.

Original Kernal: 901227-03
8-kilobyte 2364 ROM 4K * 8 bits PROM

28C265 = 32K * 8bits

Diffference in ROM size AND there are some other pin placements.
V0.1

Romselect should be /(a15 * a14 * a13) depending on ram/rom switch.


SEL0SEL1
00rom0
01rom1
10rom2
11rom3

$E000-$FFFF – ROM
57344-65535

KERNAL ROM or RAM area (8192 bytes); depends on the value of bits #0-#2 of the processor port at memory address $0001
$FFFA-$FFFF – hardware vectors

%x0x: RAM area.

%x1x: KERNAL ROM.

C64 PRG to cartridge.

I’ve got the tools and Bigred made me enthusiastic again.
My goal is to make a C64 Cartridge from a PRG. And Not any program, it is the 8085 Emulator from Sepp.

Serveral problems i have to ‘fix’

  • The program is 17K, Cartridges can only be 16K.
    So i have to use 2x 8K and compress the data.
    This means it have to be uncompressed at start time.
    ( I was thinking of using exomiser for this )
  • Program starts normally at $0820 and probably is not optimised to run anywhere else.
    So a starting routine has to copy the program from cartridge memory to the correct location

Luckily i have the source! How cool is that

For version 4.73 it states : Starting at $0820 .. but my hexdump is off by one??!?

root@battlestation:/home/fash/Projects/minipro# hexdump -C /tmp/8085.prg  | head
00000000  01 08 1e 08 c5 07 9e 32  30 38 30 20 42 59 20 4d  |.......2080 BY M|
00000010  41 52 54 49 4e 20 4d 45  59 45 52 49 4e 4b 00 00  |ARTIN MEYERINK..|
00000020  00 20 ec 08 20 7f 19 20  2b 2c 20 11 19 20 b8 08  |. .. .. +, .. ..|
00000030  20 20 2c 20 a0 2c 20 f2  2c 20 11 e1 4c 00 15 aa  |  , ., ., ..L...|
00000040  aa a2 06 ad b7 08 9d 48  d8 bd 48 04 20 88 39 9d  |.......H..H. .9.|
00000050  48 04 ca 10 ee a9 60 8d  4c 04 4c 50 47 00 a9 d0  |H.....`.L.LPG...|
00000060  2c a9 f0 8d 45 1f 4c 11  e1 1e 93 0d 20 20 4d 41  |,...E.L.....  MA|
00000070  52 54 49 4e 20 4d 45 59  45 52 49 4e 4b 27 53 0d  |RTIN MEYERINK'S.|
00000080  0d 20 38 30 38 35 20 45  4d 55 4c 41 54 4f 52 20  |. 8085 EMULATOR |
00000090  20 56 34 2e 38 30 0d 0d  20 20 28 43 29 20 31 20  | V4.80..  (C) 1 |

00000020 00 20 ec starts with 00 at $0020 .. and not 20 ?!?!

Tools used until now:

  • Vice – C64 Emulator
    x64 -cartcrt 8085.crt
  • c1541 – Linux disk tool for C64 images.
    Used this to extract the 8085emulator PRG
  • prg2crt.py – a convertor from PRG to a cartrid file which can be used by Vice
    python2 prg2crt.py 8085.prg 8085.crt
  • minipro – eeprom programming tool for Linux
    minipro -p AT28C64 -w /tmp/test.bin
  • cartconv (tool from vice to convert crt <-> bin)
    cartconv -t normal -i test.bin -n ‘my cart’ -o test.crt
  • xa – Cross assembler 65xx/R65C02/65816
  • ACME – the ACME Crossassembler for Multiple Environments
Memory Map C64 – source c64-wiki.com

Card Low starts at $8000, so that’s the place where those roms are going to be.
To place on this address:

Copy routine : from ($8000 + this copy routine) to $0820
When to decompress??
jmp routine to $0820

A cartridge file >16K and with his emulation headers seems to work??!

Also nice: Magic Desk Cartridge Generator V3.0

UPDATE: 20220811

exomizer sfx 0x0820 8085.prg -o data.exo # Compress and start at 0x0820 
xa frame.asm -o frame.bin # Add code and write binary
x64 --cart16 frame.bin # Test cartridge with Vice

frame.asm

;---------------------------------------------------------- 
; example usage
; xa frame.asm -o frame.bin
; cartconv -t normal -i frame.bin -n 'my cart' -o frame.crt
; x64 -cartcrt frame.crt
;----------------------------------------------------------

;no load-adress for bin-file, so no header here

*=$8000
.word launcher ;cold start
.word launcher ;warm start
.byte $c3	;c
.byte $c2	;b
.byte $cd	;m
.byte $38	;8
.byte $30	;0

launcher
  stx $d016
  jsr $fda3	;prepare irq
  jsr $fd50	;init memory
  jsr $fd15	;init i/o
  jsr $ff5b	;init video
                ;make sure this sets up everything you need,
                ;the calls above are probably sufficient
  ldx #$fb
  txs

;set up starting code outside of cartridge-area
move_starter
  ldx #(starter_end-starter_start)
loop1
  lda starter_start,x
  sta $100,x
  dex
  bpl loop1
  jmp $100
;---------------------------------
starter_start	
  ldx #$40 ;64 pages = 256 * 64 = 16384 Bytes
  ldy #0
loop
src
  lda exomized_data,y
dst
  sta $801,y
  iny
  bne loop
  inc src+2-starter_start+$100 
  inc dst+2-starter_start+$100
  dex
  bpl loop

;make sure settings for $01 and IRQ etc are correct for your code
;remember THIS table from AAY64:

;       Bit+-------------+-----------+------------+
;       210| $8000-$BFFF |$D000-$DFFF|$E000-$FFFF |
;  +---+---+-------------+-----------+------------+
;  | 7 |111| Cart.+Basic |    I/O    | Kernal ROM |
;  +---+---+-------------+-----------+------------+
;  | 6 |110|     RAM     |    I/O    | Kernal ROM |
;  +---+---+-------------+-----------+------------+
;  | 5 |101|     RAM     |    I/O    |    RAM     |
;  +---+---+-------------+-----------+------------+
;  | 4 |100|     RAM     |    RAM    |    RAM     |
;  +---+---+-------------+-----------+------------+
;  | 3 |011| Cart.+Basic | Char. ROM | Kernal ROM |
;  +---+---+-------------+-----------+------------+
;  | 2 |010|     RAM     | Char. ROM | Kernal ROM |
;  +---+---+-------------+-----------+------------+
;  | 1 |001|     RAM     | Char. ROM |    RAM     |
;  +---+---+-------------+-----------+------------+
;  | 0 |000|     RAM     |    RAM    |    RAM     |
;  +---+---+-------------+-----------+------------+

  lda #$35 ;cart is always on instead of BASIC unless it can be switched off via software
  sta $01
  jmp $80d ;for exomizer, i.e.

starter_end
;----------------------------------
exomized_data
.bin 2,0,"data.exo"
;syntax for exomizer 2.0.1:
;exomizer sfx sys game.prg -o data.exo
main_file_end
;fill up full $4000 bytes for bin file ($c000-$8000=$4000)
.dsb ($c000-main_file_end),0

Exomiser info

 Reading "8085.prg", loading from $0801 to $4CE9.
 Crunching from $0801 to $4CE9.
Phase 1: Instrumenting file
-----------------------------
 Length of indata: 17640 bytes.
 [building.directed.acyclic.graph.building.directed.acyclic.graph.]
 Instrumenting file, done.

Phase 2: Calculating encoding
-----------------------------
 pass 1: optimizing ..
 [finding.shortest.path.finding.shortest.path.finding.shortest.pat]
  size 80273.0 bits ~10035 bytes
 pass 2: optimizing ..
 [finding.shortest.path.finding.shortest.path.finding.shortest.pat]
  size 80039.0 bits ~10005 bytes
 pass 3: optimizing ..
 Calculating encoding, done.

Phase 3: Generating output file
------------------------------
 Encoding: 1101112133423160,1122,2010223445667788,032144406789BBCD
 Length of crunched data: 10034 bytes.
 Crunched data reduced 7606 bytes (43.12%)
 Target is self-decrunching C64 executable,
 jmp address $0820.
 Writing "data.exo" as prg, saving from $0801 to $304C.
Memory layout:   |Start |End   |
 Crunched data   | $07E7| $2F18|
 Decrunched data | $0801| $4CE9|
 Decrunch table  | $0334| $03D0|
 Decruncher      | $00FD| $01C0| and $9F,$A7,$AE,$AF
 Decrunch effect writes to $DBE7.
Decruncher:  |Enter |During|Exit  |
 RAM config  |   $37|   $37|   $37|
 IRQ enabled |     1|     1|     1|

UPDATE:20230126

; CODE COPY FROM http://www.lemon64.com/forum/viewtopic.php?t=60786&sid=2559442c8b963d7aac27cb13b493f372
; Thanks for posting: Richard of TND
; this is for a 16KB cart, using ACME!! 

      !to "mycart.crt",cart16crt 

scr = $0400 

DecrunchADDR = 2061 ;SYS 2061   (HEX $080D) 

      *=$8000 
      !word launcher 
      !word launcher 
      !byte $c3,$c2,$cd,$38,$30 ;CBM 80 
      
      

launcher 
   sei 
   stx $d016 
   jsr $fda3 ;prepare irq 
   jsr $fd50 ;input memory 
   jsr $fd15 ;initialise i/o 
   jsr $ff5b ;initialise video memory 
 
;For a more professional boot up. Make 
;the border and screen black. AFTER 
;the video memory, etc has finished. 

   lda #$00 
   sta $d020 
   sta $d021 
   cli 

;Switch off the screen. 

   lda $d011 
   and #%11101111 
   sta $d011 

;Move transfer code over to the screen 
;memory. 

   ldx #$00 
tloop   lda transfer,x 
   sta scr,x 
   inx 
   bne tloop 
   jmp scr 

transfer 
   ldx #$00 
tr1      lda linkedgame,x         ;Move from linked address 
  sta $0801,x                        ;Direct to BASIC start address 
   inx 
   bne tr1 
   inc scr+4 
   inc scr+7 
   lda scr+4 
   bne transfer 
   jsr $e453 ;load basic vectors 
   jsr $e3bf ;init basic ram 

   ldx #$fb 
   txs 

   ;Execute the game, by jumping to the 
   ;de-cruncher's start address. 
   ;jmp $0820 
   jmp DecrunchADDR


;Link crunched game as a PRG file to memory after 
;the cartridge build code. 

linkedgame 
   !bin "8085sys.prg",,2 

FileSize = * 
!if FileSize >$c000 { 
!error "FILE SIZE IS TOO BIG TO FIT 16KB CARTRIDGE" 
} else { 

   *=$c000 
} 

Exomizer:

exomizer sfx sys  8085.prg -o 8085sys.prg
 Reading "8085.prg", loading from $0801 to $4CE9.
 Crunching from $0801 to $4CE9.
Phase 1: Instrumenting file
-----------------------------
 Length of indata: 17640 bytes.
 [building.directed.acyclic.graph.building.directed.acyclic.graph.]
 Instrumenting file, done.

Phase 2: Calculating encoding
-----------------------------
 pass 1: optimizing ..
 [finding.shortest.path.finding.shortest.path.finding.shortest.pat]
  size 80273.0 bits ~10035 bytes
 pass 2: optimizing ..
 [finding.shortest.path.finding.shortest.path.finding.shortest.pat]
  size 80039.0 bits ~10005 bytes
 pass 3: optimizing ..
 Calculating encoding, done.

Phase 3: Generating output file
------------------------------
 Encoding: 1101112133423160,1122,2010223445667788,032144406789BBCD
 Length of crunched data: 10034 bytes.
 Crunched data reduced 7606 bytes (43.12%)
 Target is self-decrunching C64 executable,
 jmp address $0820.
 Writing "8085sys.prg" as prg, saving from $0801 to $304C.
Memory layout:   |Start |End   |
 Crunched data   | $07E7| $2F18|
 Decrunched data | $0801| $4CE9|
 Decrunch table  | $0334| $03D0|
 Decruncher      | $00FD| $01C0| and $9F,$A7,$AE,$AF
 Decrunch effect writes to $DBE7.
Decruncher:  |Enter |During|Exit  |
 RAM config  |   $37|   $37|   $37|
 IRQ enabled |     1|     1|     1|
exomizer sfx $\0801 8085.prg -o 8085out.prg
 Reading "8085.prg", loading from $0801 to $4CE9.
 Crunching from $0801 to $4CE9.
Phase 1: Instrumenting file
-----------------------------
 Length of indata: 17640 bytes.
 [building.directed.acyclic.graph.building.directed.acyclic.graph.]
 Instrumenting file, done.

Phase 2: Calculating encoding
-----------------------------
 pass 1: optimizing ..
 [finding.shortest.path.finding.shortest.path.finding.shortest.pat]
  size 80273.0 bits ~10035 bytes
 pass 2: optimizing ..
 [finding.shortest.path.finding.shortest.path.finding.shortest.pat]
  size 80039.0 bits ~10005 bytes
 pass 3: optimizing ..
 Calculating encoding, done.

Phase 3: Generating output file
------------------------------
 Encoding: 1101112133423160,1122,2010223445667788,032144406789BBCD
 Length of crunched data: 10034 bytes.
 Crunched data reduced 7606 bytes (43.12%)
 Target is self-decrunching C64 executable,
 jmp address $0801.
 Writing "8085out.prg" as prg, saving from $0801 to $304C.
Memory layout:   |Start |End   |
 Crunched data   | $07E7| $2F18|
 Decrunched data | $0801| $4CE9|
 Decrunch table  | $0334| $03D0|
 Decruncher      | $00FD| $01C0| and $9F,$A7,$AE,$AF
 Decrunch effect writes to $DBE7.
Decruncher:  |Enter |During|Exit  |
 RAM config  |   $37|   $37|   $37|
 IRQ enabled |     1|     1|     1|

This looks okay: (monitor in vice)

Attaching crt in vice

Maybe one of these problems:

1) you CAN NOT use BASIC routines when a cart is inserted (without weird tricks, i.e.
storing BASIC routines on cart etc)

2) you need to be careful about $01 as you may map in ROM at $8000 without expecting it.

Please refer to this if in doubt:
http://unusedino.de/ec64/technical/aay/c64/memcfg.html

[3] You should also be careful about the usage of KERNAL routines as some of them
sweep across BASIC-code as well!