// Porting to (inline) assembly, moving more things to zeropage

#include <peekpoke.h>

#define DEFAULT_SCREEN ((unsigned char*)0x400)
#define COLOR_RAM ((unsigned char*)0xD800)

static const char palette[5] = {0,9,2,7,1};

static const unsigned char charset[8*64*4] = { // 64 ECM characters - a dither pattern
 0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,2,0,32,0,0,0,0,4,0,32,0,8,0,0,0,4,16,0,64,4,0,0,0,0,18,0,64,0,10,0,64,8,0,2,16,0,66,0,128,4,32,2,0,8,65,0,
 0,32,2,136,0,34,136,0,0,18,64,8,18,0,66,8,32,1,168,0,2,16,66,8,9,32,4,160,1,8,160,2,16,130,20,0,74,4,80,2,1,72,2,36,144,66,8,34,40,129,40,10,160,8,66,8,8,33,44,64,42,64,21,128,
 65,42,0,41,2,88,34,9,9,69,32,138,16,82,8,162,146,0,90,66,144,9,68,146,148,66,53,130,52,64,137,32,168,68,145,66,24,130,105,18,65,42,72,150,33,204,1,50,171,8,169,2,88,34,169,36,16,85,170,85,82,132,73,34,
 181,74,162,169,20,72,81,136,149,82,102,88,13,162,4,85,138,41,230,26,160,170,84,145,202,119,1,117,130,84,155,66,165,86,241,78,40,141,80,50,90,155,213,43,241,6,84,18,84,187,208,71,42,153,101,170,74,185,85,250,171,84,133,82,
 54,91,165,186,21,106,85,154,213,109,134,185,12,247,137,86,170,117,212,45,154,226,93,182,37,170,213,62,233,181,86,173,109,178,173,107,214,42,222,181,106,183,218,117,148,91,237,181,78,233,190,213,121,207,114,173,218,167,89,175,90,247,173,118,
 53,238,181,235,86,237,159,117,85,238,181,87,253,86,191,109,174,187,110,173,119,222,183,234,118,219,237,151,253,106,191,218,109,247,157,246,191,85,253,214,249,166,253,175,217,191,230,189,106,223,117,251,223,181,127,213,118,247,93,235,189,247,125,215,
 215,125,174,251,93,255,183,222,247,189,239,254,171,222,251,175,189,247,191,109,251,223,182,251,191,237,183,125,239,253,191,238,223,251,190,247,239,125,247,222,246,223,251,126,223,255,251,111,223,251,191,245,127,237,255,239,247,191,253,239,254,239,187,255,
 251,255,127,247,238,255,191,247,223,251,255,191,247,253,191,255,255,239,255,175,255,254,223,255,255,191,247,255,255,253,191,255,255,239,255,255,255,251,127,255,255,255,223,255,255,253,255,255,255,255,255,247,255,255,255,255,255,255,255,255,255,255,255,255,
 0,0,0,255,255,0,0,0,8,28,62,127,127,28,62,0,24,24,24,24,24,24,24,24,0,0,0,255,255,0,0,0,0,0,255,255,0,0,0,0,0,255,255,0,0,0,0,0,0,0,0,0,255,255,0,0,48,48,48,48,48,48,48,48,
 12,12,12,12,12,12,12,12,0,0,0,224,240,56,24,24,24,24,28,15,7,0,0,0,24,24,56,240,224,0,0,0,192,192,192,192,192,192,255,255,192,224,112,56,28,14,7,3,3,7,14,28,56,112,224,192,255,255,192,192,192,192,192,192,
 255,255,3,3,3,3,3,3,0,60,126,126,126,126,60,0,0,0,0,0,0,255,255,0,54,127,127,127,62,28,8,0,96,96,96,96,96,96,96,96,0,0,0,7,15,28,24,24,195,231,126,60,60,126,231,195,0,60,126,102,102,126,60,0,
 24,24,102,102,24,24,60,0,6,6,6,6,6,6,6,6,8,28,62,127,62,28,8,0,24,24,24,255,255,24,24,24,192,192,48,48,192,192,48,48,24,24,24,24,24,24,24,24,0,0,3,62,118,54,54,0,255,127,63,31,15,7,3,1,
 0,0,0,0,0,0,0,0,240,240,240,240,240,240,240,240,0,0,0,0,255,255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,192,192,192,192,192,192,192,192,204,204,51,51,204,204,51,51,3,3,3,3,3,3,3,3,
 0,0,0,0,204,204,51,51,255,254,252,248,240,224,192,128,3,3,3,3,3,3,3,3,24,24,24,31,31,24,24,24,0,0,0,0,15,15,15,15,24,24,24,31,31,0,0,0,0,0,0,248,248,24,24,24,0,0,0,0,0,0,255,255,
 0,0,0,31,31,24,24,24,24,24,24,255,255,0,0,0,0,0,0,255,255,24,24,24,24,24,24,248,248,24,24,24,192,192,192,192,192,192,192,192,224,224,224,224,224,224,224,224,7,7,7,7,7,7,7,7,255,255,0,0,0,0,0,0,
 255,255,255,0,0,0,0,0,0,0,0,0,0,255,255,255,3,3,3,3,3,3,255,255,0,0,0,0,240,240,240,240,15,15,15,15,0,0,0,0,24,24,24,248,248,0,0,0,240,240,240,240,0,0,0,0,240,240,240,240,15,15,15,15,
 195,153,145,145,159,153,195,255,231,195,153,129,153,153,153,255,131,153,153,131,153,153,131,255,195,153,159,159,159,153,195,255,135,147,153,153,153,147,135,255,129,159,159,135,159,159,129,255,129,159,159,135,159,159,159,255,195,153,159,145,153,153,195,255,
 153,153,153,129,153,153,153,255,195,231,231,231,231,231,195,255,225,243,243,243,243,147,199,255,153,147,135,143,135,147,153,255,159,159,159,159,159,159,129,255,156,136,128,148,156,156,156,255,153,137,129,129,145,153,153,255,195,153,153,153,153,153,195,255,
 131,153,153,131,159,159,159,255,195,153,153,153,153,195,241,255,131,153,153,131,135,147,153,255,195,153,159,195,249,153,195,255,129,231,231,231,231,231,231,255,153,153,153,153,153,153,195,255,153,153,153,153,153,195,231,255,156,156,156,148,128,136,156,255,
 153,153,195,231,195,153,153,255,153,153,153,195,231,231,231,255,129,249,243,231,207,159,129,255,195,207,207,207,207,207,195,255,243,237,207,131,207,157,3,255,195,243,243,243,243,243,195,255,255,231,195,129,231,231,231,231,255,239,207,128,128,207,239,255,
 255,255,255,255,255,255,255,255,231,231,231,231,255,255,231,255,153,153,153,255,255,255,255,255,153,153,0,153,0,153,153,255,231,193,159,195,249,131,231,255,157,153,243,231,207,153,185,255,195,153,195,199,152,153,192,255,249,243,231,255,255,255,255,255,
 243,231,207,207,207,231,243,255,207,231,243,243,243,231,207,255,255,153,195,0,195,153,255,255,255,231,231,129,231,231,255,255,255,255,255,255,255,231,231,207,255,255,255,129,255,255,255,255,255,255,255,255,255,231,231,255,255,252,249,243,231,207,159,255,
 195,153,145,137,153,153,195,255,231,231,199,231,231,231,129,255,195,153,249,243,207,159,129,255,195,153,249,227,249,153,195,255,249,241,225,153,128,249,249,255,129,159,131,249,249,153,195,255,195,153,159,131,153,153,195,255,129,153,243,231,231,231,231,255,
 195,153,153,195,153,153,195,255,195,153,153,193,249,153,195,255,255,255,231,255,255,231,255,255,255,255,231,255,255,231,231,207,241,231,207,159,207,231,241,255,255,255,129,255,129,255,255,255,143,231,243,249,243,231,143,255,195,153,249,243,231,255,231,255,
 255,255,255,0,0,255,255,255,247,227,193,128,128,227,193,255,231,231,231,231,231,231,231,231,255,255,255,0,0,255,255,255,255,255,0,0,255,255,255,255,255,0,0,255,255,255,255,255,255,255,255,255,0,0,255,255,207,207,207,207,207,207,207,207,
 243,243,243,243,243,243,243,243,255,255,255,31,15,199,231,231,231,231,227,240,248,255,255,255,231,231,199,15,31,255,255,255,63,63,63,63,63,63,0,0,63,31,143,199,227,241,248,252,252,248,241,227,199,143,31,63,0,0,63,63,63,63,63,63,
 0,0,252,252,252,252,252,252,255,195,129,129,129,129,195,255,255,255,255,255,255,0,0,255,201,128,128,128,193,227,247,255,159,159,159,159,159,159,159,159,255,255,255,248,240,227,231,231,60,24,129,195,195,129,24,60,255,195,129,153,153,129,195,255,
 231,231,153,153,231,231,195,255,249,249,249,249,249,249,249,249,247,227,193,128,193,227,247,255,231,231,231,0,0,231,231,231,63,63,207,207,63,63,207,207,231,231,231,231,231,231,231,231,255,255,252,193,137,201,201,255,0,128,192,224,240,248,252,254,
 255,255,255,255,255,255,255,255,15,15,15,15,15,15,15,15,255,255,255,255,0,0,0,0,0,255,255,255,255,255,255,255,255,255,255,255,255,255,255,0,63,63,63,63,63,63,63,63,51,51,204,204,51,51,204,204,252,252,252,252,252,252,252,252,
 255,255,255,255,51,51,204,204,0,1,3,7,15,31,63,127,252,252,252,252,252,252,252,252,231,231,231,224,224,231,231,231,255,255,255,255,240,240,240,240,231,231,231,224,224,255,255,255,255,255,255,7,7,231,231,231,255,255,255,255,255,255,0,0,
 255,255,255,224,224,231,231,231,231,231,231,0,0,255,255,255,255,255,255,0,0,231,231,231,231,231,231,7,7,231,231,231,63,63,63,63,63,63,63,63,31,31,31,31,31,31,31,31,248,248,248,248,248,248,248,248,0,0,255,255,255,255,255,255,
 0,0,0,255,255,255,255,255,255,255,255,255,255,0,0,0,252,252,252,252,252,252,0,0,255,255,255,255,15,15,15,15,240,240,240,240,255,255,255,255,231,231,231,7,7,255,255,255,15,15,15,15,255,255,255,255,15,15,15,15,240,240,240,240,
};

void init(void) { 
  register unsigned short i16;
  
  // Initialize random number gen (SID noise waveform)
  POKE(54286,255); // max frequency
  POKE(54287,255); // max frequency
  POKE(54290,128); // voice 3 to noise
  
  POKE(53280, 0); // black border color 
  
  // Initialize the ECM mode and character set  
  POKE(53265, PEEK(53265)|64); // Sets bit 6 in $D011, turns off BMM
  POKE(53281, palette[0]); // color1 - $D021
  POKE(53282, palette[1]);
  POKE(53283, palette[2]);
  POKE(53284, palette[3]);
  
  for(i16=0;i16<2048;i16++){ // copy the charset to 0x2000
    POKE(8192+i16, charset[i16]);
  }
  
  POKE(53272, (PEEK(53272) & 240)|8 ); // point vic2 to the new charset
}

// NOTE: because of preprocessor to string, L has to be an integer, can't be an expression, even if constant
// ror ror ror and - better than 6 lsr... (need 3 because ror goes into the carry)
#define ASM_LINE2(L) \
__asm__("ldx #40");\
__asm__("@L2_" #L ":");\
__asm__("lda %w,x", 0x400+L+39);\
__asm__("adc %w,x", 0x400+L+41);\
__asm__("adc %w,x", 0x400+L+80);\
__asm__("lsr");\
__asm__("lsr");\
__asm__("sta %w,x", 0x400+L);\
__asm__("rol");\
__asm__("rol");\
__asm__("rol");\
__asm__("and #3");\
__asm__("tay");\
__asm__("lda $f0,y");\
__asm__("sta %w,x", 0xD800+L);\
__asm__("dex");\
__asm__("bpl @L2_" #L );
#define FAST_LINE2(L) \
 for(iii8=39;;iii8--){ \
   ii8 = PEEK(DEFAULT_SCREEN + L + 39 + iii8); \
   ii8 += PEEK(DEFAULT_SCREEN + L + 41 + iii8); \
   ii8 += PEEK(DEFAULT_SCREEN + L + 80 + iii8); \
   ii8 >>= 2; \
   POKE(DEFAULT_SCREEN + L + iii8, ii8); \
   POKE(COLOR_RAM + L + iii8, palette[1 + (ii8>>6)]); \
   if(iii8==0) break; \
}

#define ASM_LINE(L) \
__asm__("ldx #40");\
__asm__("@L2_" #L ":");\
__asm__("lda %w,x", 0x400+L+39);\
__asm__("adc %w,x", 0x400+L+41);\
__asm__("lsr");\
__asm__("lsr");\
__asm__("sta $ff");\
__asm__("lda %w,x", 0x400+L+40);\
__asm__("adc %w,x", 0x400+L+80);\
__asm__("lsr");\
__asm__("lsr");\
__asm__("adc $ff");\
__asm__("sbc #5");\
//__asm__("bpl @L_" #L );\
//__asm__("lda #0");\
//__asm__("@L_" #L ":");\
__asm__("sta %w,x", 0x400+L);\
__asm__("rol");\
__asm__("rol");\
__asm__("rol");\
__asm__("and #3");\
__asm__("tay");\
__asm__("lda $f0,y");\
__asm__("sta %w,x", 0xD800+L);\
__asm__("dex");\
__asm__("bpl @L2_" #L );
#define FAST_LINE(L) \
 for(iii8=39;;iii8--){ \
   ii8 = PEEK(DEFAULT_SCREEN + L + 39 + iii8); \
   ii8 += PEEK(DEFAULT_SCREEN + L + 41 + iii8); \
   ii8 >>= 2; \
   i8 = PEEK(DEFAULT_SCREEN + L + 40 + iii8); \
   i8 += PEEK(DEFAULT_SCREEN + L + 80 + iii8); \
   i8 >>= 2; \
   ii8 = ii8 + i8 - 5; \
   if(ii8>128) ii8 = 0; \
   POKE(DEFAULT_SCREEN + L + iii8, ii8); \
   POKE(COLOR_RAM + L + iii8, palette[1 + (ii8>>6)]); \
   if(iii8==0) break; \
}

// uses zeropage fc to ff (inclusive)
#define ASM_LINE_S(L) \
__asm__("ldx #40");\
__asm__("@L2_" #L ":");\
__asm__("lda %w,x", 0x400+L+39);\
__asm__("adc %w,x", 0x400+L+41);\
__asm__("sta $fe");\
__asm__("lda #0");\
__asm__("adc #0");\
__asm__("sta $ff");\
__asm__("lda %w,x", 0x400+L+40);\
__asm__("adc %w,x", 0x400+L+80);\
__asm__("sta $fc");\
__asm__("lda #0");\
__asm__("adc #0");\
__asm__("sta $fd");\
__asm__("lda $fe");\
__asm__("adc $fc");\
__asm__("sta $fe");\
__asm__("lda $ff");\
__asm__("adc $fd");\
__asm__("sta $ff");\
__asm__("lsr $ff");\
__asm__("ror $fe");\
__asm__("lsr $ff");\
__asm__("ror $fe");\
__asm__("lda $fe");\
__asm__("sbc #6");\
__asm__("sta %w,x", 0x400+L);\
__asm__("rol");\
__asm__("rol");\
__asm__("rol");\
__asm__("and #3");\
__asm__("tay");\
__asm__("lda $f0,y");\
__asm__("sta %w,x", 0xD800+L);\
__asm__("dex");\
__asm__("bpl @L2_" #L );
#define SLOW_LINE(L) \
 for(iii8=39;;iii8--){ \
   ii16 = PEEK(DEFAULT_SCREEN + L + 39 + iii8); \
   ii16 += PEEK(DEFAULT_SCREEN + L + 40 + iii8); \
   ii16 += PEEK(DEFAULT_SCREEN + L + 41 + iii8); \
   ii16 += PEEK(DEFAULT_SCREEN + L + 80 + iii8); \
   ii16 = (ii16>>2) - 6; \
   if(ii16>255) ii16 = 0; \
   ii8 = ii16; \
   POKE(DEFAULT_SCREEN + L + iii8, ii8); \
   POKE(COLOR_RAM + L + iii8, palette[1 + (ii8>>6)]); \
   if(iii8==0) break; \
}

void main(void) {
  // "register" forces variables to the zero-page
  // ZP range is defined in c64.cfg for cc65: start = $0002, size = $001A;
  register unsigned char i8, ii8, iii8;
  register unsigned short i16, ii16;
  
  init();
  __asm__("sei"); // disable interrupts

  // Move the palette for the lines to zeropage f0-f3
  //static const char palette[5] = {0,9,2,7,1};
  __asm__("lda #9");
  __asm__("sta $f0");
  __asm__("lda #2");
  __asm__("sta $f1");
  __asm__("lda #7");
  __asm__("sta $f2");
  __asm__("lda #1");
  __asm__("sta $f3");
  
  while(1){ 
       
#if 1 // all assembly
    __asm__("ldx #40");
    __asm__("@L2_:");
    __asm__("lda %w", (unsigned short)54299);
    __asm__("sta %w,x", 0x400+(40*24));
    __asm__("rol");
    __asm__("rol");
    __asm__("rol");
    __asm__("and #3");
    __asm__("tay");
    __asm__("lda $f0,y");
    __asm__("sta %w,x", 0xD800+(40*24));
    __asm__("dex");
    __asm__("bpl @L2_");
    
    ASM_LINE2(0);
    ASM_LINE2(40);
    ASM_LINE2(80);
    ASM_LINE2(120);
    ASM_LINE2(160);
    ASM_LINE2(200);
    ASM_LINE2(240);
    ASM_LINE2(280);
    ASM_LINE2(320);
    ASM_LINE(360);
    ASM_LINE(400);
    ASM_LINE(440);
    ASM_LINE(480);    
    ASM_LINE(520);
    ASM_LINE(560);    
    ASM_LINE_S(600);    
    ASM_LINE_S(640);    
    ASM_LINE_S(680);    
    ASM_LINE_S(720);      
    ASM_LINE_S(760);    
    ASM_LINE_S(800);    
    ASM_LINE_S(840);    
    ASM_LINE_S(880);    
    ASM_LINE_S(920);    
#else // C implementation
    for(i8=0;i8<40;i8++) { // rnd numbers on the last line
      ii8 = PEEK(54299);
      POKE(DEFAULT_SCREEN+(40*24)+i8, ii8);
      POKE(COLOR_RAM+(40*24)+i8, palette[1 + (ii8>>6)]);
    }
    
    FAST_LINE2(0);
    FAST_LINE2(40);
    FAST_LINE2(80);
    FAST_LINE2(120);
    FAST_LINE2(160);
    FAST_LINE2(200);
    FAST_LINE2(240);
    FAST_LINE2(280);
    FAST_LINE2(320);
    FAST_LINE(360);
    FAST_LINE(10*40);
    FAST_LINE(11*40);
    FAST_LINE(12*40);    
    FAST_LINE(13*40);
    FAST_LINE(14*40);    
    SLOW_LINE(15*40);    
    SLOW_LINE(16*40);    
    SLOW_LINE(17*40);    
    SLOW_LINE(18*40);      
    SLOW_LINE(19*40);    
    SLOW_LINE(20*40);    
    SLOW_LINE(21*40);    
    SLOW_LINE(22*40);    
    SLOW_LINE(23*40);
#endif
  }
  
  return;
}