Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Set screen RAM to $F000 on C64

368 views
Skip to first unread message

Payton Byrd

unread,
Mar 16, 2011, 1:13:58 AM3/16/11
to
I am trying to use the memory under the kernel for screen RAM on the 64. I already have code to prepare the memory at $F000 with the data that I want displayed, but when I try to set DD00 and D018 appropriately, I get garbage. What is the correct way of doing it?

Thanks

dott.Piergiorgio

unread,
Mar 16, 2011, 3:43:41 AM3/16/11
to
Il 16/03/2011 06:13, Payton Byrd ha scritto:
> I am trying to use the memory under the kernel for screen RAM on the 64. I already have code to prepare the memory at $F000 with the data that I want displayed, but when I try to set DD00 and D018 appropriately, I get garbage. What is the correct way of doing it?

if disassembling the "garbage" reveals that isn't garbeage, what is
wrong ought to be in the handling of 6510 control port. Normally,
writing in a location in the rom area writes in the ram and reading it
gives the value in the rom.

Pages 5.39 to 5.46 of the PRG describes the use of the 6510 control port
and the memory maps obtainable thru the manipultation of the control
register.

HTH and

Best regards from Italy,
dott. Piergiorgio.


iAN CooG

unread,
Mar 16, 2011, 6:33:38 PM3/16/11
to

You probably set wrong d018 value or even forgot to add your own charset. If
you want to use ROM charset simply copy it somewhere in the same bank, it's
handy to have it on the same ROM address at $d000, the RAM under $d000 is
rarely used.

*=$0801
word eop
word 7102
byte $9e,"2061",0
eop
word 0
;-------------------------
charset = $d000
screen = $f000
;calc d018/bank values
ns = >screen<<2
nc = [>charset&$3f]>>2
v18 = [ns|nc]&$ff
bank = 3-[>screen>>6]
;-------------------------

; save cursorpos
jsr $e513
stx $fd
sty $fe

; set the vic bank and screen/charset in use
lda #v18
sta $d018
lda $dd00
and #$fc
ora #bank
sta $dd00

; copy charset from chargen to the RAM at the same address
; else load your favourite charset here
sei
ldx #$08
lda #$33 ; see the chargen at $d000
sta $01
lda #>charset
sta $fc
ldy #$00
sty $fb
lp1
lda ($fb),y
inc $01
sta ($fb),y
dec $01
iny
bne lp1
inc $fc
dex
bne lp1
lda #$37 ; ROM active
sta $01
cli

; now let's "print" something by writing directly on the new screen.
; write on RAM while ROM is active, VIC-II always sees the RAM
; apart the chargen shadow copies at $1xxx and $9xxx.
ldy #[endtext-ctext-1]
ptext
lda ctext,y
sta screen,y
dey
bpl ptext
jsr k1

; the KERNAL still uses the screen at $0400
; let's point it to the new screen
lda #>screen
sta $0288
jsr $e544
ldy #>ttext
lda #<ttext
jsr $ab1e
jsr k1

; now let's get back to normal (beware: color RAM is altered)
lda #$04
sta $0288
lda #$14
sta $d018
lda $dd00
and #$fc
ora #$03
sta $dd00
ldx $fd
ldy $fe
jmp $e50c

;--------------
k1
jsr $ffe4
beq k1
rts

ctext
scru "THIS TEXT WILL APPEAR AT $F000"
endtext

ttext
asc "THIS IS PRINTED WITH "
byte $9e,$12
asc "JSR $AB1E"
byte $92,$0d,$9a
asc "ON THE NEW SCREEN"
byte 0


http://iancoog.altervista.org/hid/screenf000.zip

--
-=[]=--- iAN CooG/HVSC & C64Intros ---=[]=-
I love you!, ohh mhhh, ahhh... Please Insert Coin to Continue!


BruceMcF

unread,
Mar 16, 2011, 7:11:33 PM3/16/11
to
On Mar 16, 1:13 am, Payton Byrd <plb...@gmail.com> wrote:
> I am trying to use the memory under the kernel for screen RAM on the 64.  I already have code to prepare the memory at $F000 with the data that I want displayed, but when I try to set DD00 and D018 appropriately, I get garbage.  What is the correct way of doing it?
>
> Thanks

Character or bitmap? If Character, likely what iAN CooG said. AFAIR,
iAN CooG is right on about the RAM at $D000, underneath the Device
memory space and Character ROM as a good place to put a stable soft
character map.

The "golden RAM" at $C000 is good for one that may be rewritten on the
fly (as with some tiled games) ~ and if you flip character map pointer
at the right line, you can have text tiles on the top part of the
screen and text input/output on the bottom.

Obviously bitmapped screen doesn't care about character sets.

iAN CooG

unread,
Mar 16, 2011, 7:48:19 PM3/16/11
to
BruceMcF <agi...@netscape.net> wrote:
> On Mar 16, 1:13 am, Payton Byrd <plb...@gmail.com> wrote:
>> I am trying to use the memory under the kernel for screen RAM on the
>> 64. I already have code to prepare the memory at $F000 with the data

> Character or bitmap?

He talks about character (text) screen of course, bitmap can't be at $f000
but $e000-$ff3f (or c000-df3f).

--
-=[]=--- iAN CooG/HVSC & C64Intros ---=[]=-

without words


Payton Byrd

unread,
Mar 17, 2011, 1:10:38 AM3/17/11
to
I've worked through the process with the aid of the C64 PRG pages 100-106. Here's the resulting code in C (use cc65 to compile).

#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
#include <stdbool.h>
#include <string.h>

void saveScreen(void);
void retrieveScreen(void);

bool initialized = false;
unsigned char d018;
unsigned char dd00;
unsigned char dd02;

void beginDoubleBuffer(void)
{
// We need to ensure that the character set is available when the
// VIC-II is pointed at the alternate screen location of $F000.
if(!initialized)
{
*(unsigned int*)(0xDC0E) = *(unsigned int*)(0xDC0E) & 0xFE; // Turn off interrupts
*(unsigned int*)(0x01) = *(unsigned int*)(0x01) & 0xFB; // Switch in RAM

memcpy( // Copy character set from ROM to RAM at $F800
(void*)0xF800,
(void*)0xD800,
0x0800);

*(unsigned int*)(0x01) = *(unsigned int*)(0x01) | 0x04; // Switch out RAM
*(unsigned int*)(0xDC0E) = *(unsigned int*)(0xDC0E) | 0x01; // Turn on interrupts
initialized = true;
}

// Save original values
d018 = *(unsigned int*)(0xD018);
dd00 = *(unsigned int*)(0xDD00);
dd02 = *(unsigned int*)(0xDD02);

// This is an assembler routine to save the screen under Kernel ROM at $F000
saveScreen();

// Make sure bits 0 and 1 are set to outputs
*(unsigned int*)(0xDD02) = *(unsigned int*)(0xDD02) | 0x03;

// Change banks
*(unsigned int*)(0xDD00) = (*(unsigned int*)(0xDD00) & 0xFC) | 0x00;

// Change screen memory offset
*(unsigned int*)(0xD018) = (*(unsigned int*)(0xD018) & 0x0F) | 0xC0;

// Change character set offset
*(unsigned int*)(0xD018) = (*(unsigned int*)(0xD018) & 0xF0) | 0x0E;
}

void endDoubleBuffer(void)
{
// Restore original values
*(unsigned int*)(0xDD02) = dd02;
*(unsigned int*)(0xDD00) = dd00;
*(unsigned int*)(0xD018) = d018;
}


int main(void)
{
clrscr();
(void)textcolor(COLOR_WHITE);
gotoxy(0, 19);
cprintf("Entering double buffer.");
gotoxy(0, 20);
cprintf("Press key to leave double buffer.");

beginDoubleBuffer();

(void)textcolor(COLOR_CYAN);
gotoxy(0, 21);
cprintf("During double buffer.");

(void)cgetc();

endDoubleBuffer();

(void)textcolor(COLOR_LIGHTBLUE);
gotoxy(0, 22);
cprintf("After double buffer.");

return EXIT_SUCCESS;
}

MagerValp

unread,
Mar 17, 2011, 3:37:13 AM3/17/11
to
On 17 mar, 06:10, Payton Byrd <plb...@gmail.com> wrote:
>         d018 = *(unsigned int*)(0xD018);
>         dd00 = *(unsigned int*)(0xDD00);
>         dd02 = *(unsigned int*)(0xDD02);

These, and all others, should be *(unsigned char *), right now you're
doing 16-bit peeks and pokes. You should consider #include
<peekpoke.h> though, and use PEEK() and POKE() instead, as they are
much easier to read. If you #include <c64.h> you can also use symbolic
names, like VIC.ctrl2, CIA2.pra, and CIA2.ddra.

iAN CooG

unread,
Mar 17, 2011, 11:17:26 AM3/17/11
to
Payton Byrd <plb...@gmail.com> wrote:
> I've worked through the process with the aid of the C64 PRG pages
> 100-106. Here's the resulting code in C (use cc65 to compile).

(snip of C code)

Don't you feel that all this is a bit awkward, when in asm it's so simple to
achieve? You're spending a lot of time to make this work in C when in asm
it's done in few instructions and ACTUALLY works, always. C on C64 is a
waste of time for these low level things, use it only for what it's worth.
Anyway seems that you missed to set $288 to the new screen page ($f0), but
anyway cprintf seems to print always at $0400 whatever you poke there.
Switch to asm, less problems.

Payton Byrd

unread,
Mar 17, 2011, 11:19:41 AM3/17/11
to
On Thursday, March 17, 2011 2:37:13 AM UTC-5, MagerValp wrote:
> On 17 mar, 06:10, Payton Byrd
> wrote:
> >         d018 = *(unsigned int*)(0xD018);
> >         dd00 = *(unsigned int*)(0xDD00);
> >         dd02 = *(unsigned int*)(0xDD02);
>
> These, and all others, should be *(unsigned char *), right now you're
> doing 16-bit peeks and pokes. You should consider #include
>
> though, and use PEEK() and POKE() instead, as they are
> much easier to read. If you #include <c64.h> you can also use symbolic
> names, like VIC.ctrl2, CIA2.pra, and CIA2.ddra.

Thanks for the tips. I already knew about PEEKPOKE.H and actually used it when creating the code, then I converted it to pointer references to make the code smaller.

Payton Byrd

unread,
Mar 17, 2011, 2:37:14 PM3/17/11
to
I'm not an assembler programmer, I would rather spend my time actually accomplishing something than trying to rewrite the wheel (ie. all the functions such as sprintf which provide so much power in C) as assembler. I can achieve just about anything in C as you can in assembler and it's still very fast. In this case it works just fine and the code is a 1000x times easier for me to read. In the case of your example, I'd have to convert your code to an assembler function that cc65 can link against the C sources of CBM-Command, which just adds more complexity to the assembler code and takes even more time for me to accomplish.

Linards Ticmanis

unread,
Mar 17, 2011, 3:56:01 PM3/17/11
to

How does that make the code smaller by one bit, when peekpoke.h is
simply a set of macros that expand to pointer references at compile
time? Its only purpose is readability.

--
Linards Ticmanis

Payton Byrd

unread,
Mar 17, 2011, 4:22:07 PM3/17/11
to
I'm basing what I said on advice that was given to me on the cc65 mailing list on how to reduce the size of a program. If it's just macros then so be it, I was unaware of that.

Linards Ticmanis

unread,
Mar 17, 2011, 4:32:11 PM3/17/11
to

Payton,

cprintf uses the kernel screen pointer at $D1/$D2. First set $0288 to
the high byte of your video matrix, then call clrscr() to correctly
initialize the $D1/$D2 pointer.

Also why not write a function that takes the addresses of your desired
video matrix and dot data, checks them for consistency, and then sets up
$DD00, $D018 and $0288 automatically? It's a good exercise in
bit-twiddling and should make your calling code more readable.

--
Linards Ticmanis

0 new messages