?login_element?

Subversion Repositories NedoOS

Rev

Rev 129 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download

  1. /*
  2.  
  3. SjASMPlus Z80 Cross Compiler
  4.  
  5. Copyright (c) 2004-2008 Aprisobal
  6.  
  7. This software is provided 'as-is', without any express or implied warranty.
  8. In no event will the authors be held liable for any damages arising from the
  9. use of this software.
  10.  
  11. Permission is granted to anyone to use this software for any purpose,
  12. including commercial applications, and to alter it and redistribute it freely,
  13. subject to the following restrictions:
  14.  
  15. 1. The origin of this software must not be misrepresented; you must not claim
  16. that you wrote the original software. If you use this software in a product,
  17. an acknowledgment in the product documentation would be appreciated but is
  18. not required.
  19.  
  20. 2. Altered source versions must be plainly marked as such, and must not be
  21. misrepresented as being the original software.
  22.  
  23. 3. This notice may not be removed or altered from any source distribution.
  24.  
  25. */
  26.  
  27. // io_tape.cpp
  28.  
  29. #include "sjdefs.h"
  30. #include "io_tape_ldrs.h"
  31. #include <cassert>
  32.  
  33. unsigned char parity;
  34. unsigned char blocknum=1;
  35.  
  36. void writebyte(unsigned char, FILE *);
  37. void writenumber(unsigned int, FILE *);
  38. void writeword(unsigned int, FILE *);
  39. void writeheader(unsigned char, const char *, unsigned short, unsigned short, unsigned short, FILE *);
  40. void writecode(unsigned char*, aint, unsigned short, bool header, FILE *);
  41. void remove_basic_sp(unsigned char* ram);
  42. void detect_vars_changes();
  43. bool has_screen_changes();
  44. aint remove_unused_space(unsigned char* ram, aint length);
  45. aint detect_ram_start(unsigned char* ram, aint length);
  46.  
  47. int TAP_SaveEmpty(char* fname) {
  48.         FILE* ff;
  49.         if (!FOPEN_ISOK(ff, fname, "wb")) {
  50.                 Error("Error opening file", fname, IF_FIRST); return 0;
  51.         }
  52.         fclose(ff);
  53.         return 1;
  54. }
  55.  
  56. int TAP_SaveBlock(char* fname, unsigned char flag, const char *ftapname, int start, int length, int param2, int param3) {
  57.         FILE* fpout;
  58.         if (!FOPEN_ISOK(fpout, fname, "ab")) {
  59.                 Error("Error opening file", fname, FATAL);
  60.         }
  61.  
  62.         if (length + start > 0x10000) {
  63.             length = -1;
  64.         }
  65.         if (length <= 0) {
  66.             length = 0x10000 - start;
  67.         }
  68.  
  69.         int varBase = 0x80, defaultValue = 0x8000;
  70.         switch (flag) {
  71.                 case BASIC:
  72.                         if (param2 < 0) {
  73.                                 param2 = defaultValue; // no autostart
  74.                         } else if (param2 >= 16384 && param2 != defaultValue) {
  75.                                 ErrorInt("[SAVETAP] Autostart LINE out of range", param2);
  76.                         }
  77.                         if (param3 < 0) {
  78.                                 param3 = length;
  79.                         }
  80.                         break;
  81.  
  82.                 case CHARS:
  83.                         varBase = 0xC0;
  84.                 case NUMBERS:
  85.                         if (param2 <= 0) {
  86.                                 param2 = 1; // reset to default A variable
  87.                         }
  88.                         param2 &= 0x1F;
  89.                         if (param2 < 1 || param2 > 26) { // A..Z
  90.                                 Error("[SAVETAP] Variable name out of range");
  91.                         }
  92.                         param2 = (param2 | varBase) << 8;
  93.                         param3 = defaultValue;
  94.                         break;
  95.  
  96.                 case CODE:
  97.                         if (param2 < 0) {
  98.                                 param2 = start;
  99.                         }
  100.                         if (param3 < 0) {
  101.                                 param3 = defaultValue;
  102.                         }
  103.                         break;
  104.         }
  105.  
  106.         if (flag == HEADLESS) {
  107.                 flag = param3 & 0xff;
  108.         } else if (ftapname) {
  109.                 writeheader(flag, ftapname, length, param2, param3, fpout);
  110.                 flag = 0xff;
  111.         }
  112.  
  113.         writeword(length + 2, fpout);
  114.         parity = 0;
  115.         writebyte(flag, fpout);
  116.  
  117.         CDeviceSlot *S;
  118.         for (aint i = 0, ptr; i < Device->SlotsCount; i++) {
  119.             S = Device->GetSlot(i);
  120.                 if (S->Address + S->Size <= start) continue;
  121.                 if (length <= 0) break;
  122.                 assert(S->Address <= start && start < S->Address + S->Size);
  123.                 ptr = (start - S->Address);
  124.  
  125.                 while (length && ptr < S->Size) {
  126.                         writebyte(S->Page->RAM[ptr], fpout);
  127.                         ++start;
  128.                         ++ptr;
  129.                         --length;
  130.                 }
  131.         }
  132.  
  133.         writebyte(parity, fpout);
  134.         fclose(fpout);
  135.         return 1;
  136. }
  137.  
  138. int TAP_SaveSnapshot(char* fname, unsigned short start) {
  139.         FILE* fpout;
  140.         if (!FOPEN_ISOK(fpout, fname, "wb")) {
  141.                 Error("Error opening file", fname, FATAL);
  142.         }
  143.  
  144.         aint datastart = 0x5E00;
  145.         aint exeat = 0x5E00;
  146.         aint basiclen = 0x1e + 2;
  147.  
  148.         /* Filetype (0: Basic), with autostart "LINE 10" */
  149.         writeheader(0, "LOADER", basiclen, 10, basiclen, fpout);
  150.  
  151.         writeword(basiclen + 2, fpout); // length of block
  152.         parity = 0;
  153.         writebyte(0xff, fpout);
  154.         writebyte(0, fpout);
  155.         writebyte(10, fpout);           // LINE 10
  156.         writebyte(basiclen, fpout);     // basic line length
  157.         writebyte(0, fpout);
  158.  
  159.         // :CLEAR VAL "xxxxx"
  160.         writebyte(0xfd, fpout);                 // CLEAR
  161.         writebyte(0xb0, fpout);                 // VAL
  162.         writebyte('\"', fpout);
  163.         writenumber(datastart-1, fpout);
  164.         writebyte('\"', fpout);
  165.  
  166.         // :INK VAL "7"
  167.         /*writebyte(':', fpout);
  168.         writebyte(0xd9, fpout);                 // INK
  169.         writebyte(0xb0, fpout);                 // VAL
  170.         writebyte('\"', fpout);
  171.         writenumber(7, fpout);
  172.         writebyte('\"', fpout);
  173.  
  174.         // :PAPER VAL "0"
  175.         writebyte(':', fpout);
  176.         writebyte(0xda, fpout);                 // PAPER
  177.         writebyte(0xb0, fpout);                 // VAL
  178.         writebyte('\"', fpout);
  179.         writenumber(0, fpout);
  180.         writebyte('\"', fpout);
  181.  
  182.         // :BORDER VAL "0"
  183.         writebyte(':', fpout);
  184.         writebyte(0xe7, fpout);                 // BORDER
  185.         writebyte(0xb0, fpout);                 // VAL
  186.         writebyte('\"', fpout);
  187.         writenumber(0, fpout);
  188.         writebyte('\"', fpout);*/
  189.  
  190.         // :CLS
  191.         writebyte(':', fpout);
  192.         writebyte(0xfb, fpout);                 // CLS
  193.  
  194.         writebyte(':', fpout);
  195.         writebyte(0xef, fpout);      /* LOAD */
  196.         writebyte('\"', fpout);
  197.         writebyte('\"', fpout);
  198.         writebyte(0xaf, fpout);      /* CODE */
  199.         writebyte(':', fpout);
  200.         writebyte(0xf9, fpout);      /* RANDOMIZE */
  201.         writebyte(0xc0, fpout);      /* USR */
  202.         writebyte(0xb0, fpout);      /* VAL */
  203.         writebyte('\"', fpout);
  204.         writenumber(exeat, fpout);
  205.         writebyte('\"', fpout);
  206.         writebyte(0x0d, fpout);
  207.         writebyte(parity, fpout);
  208.  
  209.         if (!strcmp(DeviceID, "ZXSPECTRUM48")) {
  210.                 // prepare code block
  211.                 aint ram_length = 0xA200;
  212.                 aint ram_start = 0x0000;
  213.                 unsigned char* ram = (unsigned char*)malloc(ram_length);
  214.                 if (ram == NULL) ErrorOOM();
  215.                 memcpy(ram, (unsigned char*)Device->GetSlot(1)->Page->RAM + 0x1E00, 0x2200);
  216.                 memcpy(ram + 0x2200, (unsigned char*)Device->GetSlot(2)->Page->RAM, 0x4000);
  217.                 memcpy(ram + 0x6200, (unsigned char*)Device->GetSlot(3)->Page->RAM, 0x4000);
  218.  
  219.                 // remove basic vars
  220.                 remove_basic_sp(ram + ram_length - sizeof(ZX_STACK_DATA));
  221.  
  222.                 detect_vars_changes();
  223.  
  224.                 ram_length = remove_unused_space(ram, ram_length);
  225.                 ram_start = detect_ram_start(ram, ram_length);
  226.                 ram_length -= ram_start;
  227.  
  228.                 // write loader
  229.                 unsigned char *loader = new unsigned char[SaveTAP_ZX_Spectrum_48K_SZ];
  230.                 memcpy(loader, (char*)&SaveTAP_ZX_Spectrum_48K[0], SaveTAP_ZX_Spectrum_48K_SZ);
  231.                 if (loader == NULL) ErrorOOM();
  232.                 // Settings.LoadScreen
  233.                 loader[SaveTAP_ZX_Spectrum_48K_SZ - 7] = char(has_screen_changes());
  234.                 loader[SaveTAP_ZX_Spectrum_48K_SZ - 6] = char(start & 0x00FF);
  235.                 loader[SaveTAP_ZX_Spectrum_48K_SZ - 5] = char(start >> 8);
  236.                 loader[SaveTAP_ZX_Spectrum_48K_SZ - 4] = char((ram_start + 0x5E00) & 0x00FF);
  237.                 loader[SaveTAP_ZX_Spectrum_48K_SZ - 3] = char((ram_start + 0x5E00) >> 8);
  238.                 loader[SaveTAP_ZX_Spectrum_48K_SZ - 2] = char(ram_length & 0x00FF);
  239.                 loader[SaveTAP_ZX_Spectrum_48K_SZ - 1] = char(ram_length >> 8);
  240.                 writecode(loader, SaveTAP_ZX_Spectrum_48K_SZ, 0x5E00, true, fpout);
  241.  
  242.                 // write screen$
  243.                 if (loader[SaveTAP_ZX_Spectrum_48K_SZ - 7]) {
  244.                         writecode((unsigned char*)Device->GetSlot(1)->Page->RAM, 6912, 16384, false, fpout);
  245.                 }
  246.  
  247.                 // write code block
  248.                 writecode(ram + ram_start, ram_length, 0x5E00 + ram_start, false, fpout);
  249.  
  250.                 free(ram);
  251.         } else {
  252.                 detect_vars_changes();
  253.  
  254.                 // prepare main code block
  255.                 aint ram_length = 0x6200, ram_start = 0x0000;
  256.                 unsigned char* ram = (unsigned char*)malloc(ram_length);
  257.                 if (ram == NULL) ErrorOOM();
  258.                 memcpy(ram, (unsigned char*)Device->GetSlot(1)->Page->RAM + 0x1E00, 0x2200);
  259.                 memcpy(ram + 0x2200, (unsigned char*)Device->GetSlot(2)->Page->RAM, 0x4000);
  260.  
  261.                 ram_length = remove_unused_space(ram, ram_length);
  262.                 ram_start = detect_ram_start(ram, ram_length);
  263.                 ram_length -= ram_start;
  264.  
  265.                 // init loader
  266.                 aint loader_defsize;
  267.                 unsigned char* loader_code;
  268.                 if (!strcmp(DeviceID, "ZXSPECTRUM128")) {
  269.                         loader_defsize = SaveTAP_ZX_Spectrum_128K_SZ;
  270.                         loader_code = (unsigned char*)&SaveTAP_ZX_Spectrum_128K[0];
  271.                 } else {
  272.                         loader_defsize = SaveTAP_ZX_Spectrum_256K_SZ;
  273.                         loader_code = (unsigned char*)&SaveTAP_ZX_Spectrum_256K[0];
  274.                 }
  275.                 aint loader_len = loader_defsize + (Device->PagesCount - 2)*5;
  276.                 unsigned char *loader = new unsigned char[loader_len];
  277.                 memcpy(loader, loader_code, loader_defsize);
  278.                 if (loader == NULL) ErrorOOM();
  279.                 // Settings.Start
  280.                 loader[loader_defsize - 8] = char(start & 0x00FF);
  281.                 loader[loader_defsize - 7] = char(start >> 8);
  282.                 // Settings.MainBlockStart
  283.                 loader[loader_defsize - 6] = char((ram_start + 0x5E00) & 0x00FF);
  284.                 loader[loader_defsize - 5] = char((ram_start + 0x5E00) >> 8);
  285.                 // Settings.MainBlockLength
  286.                 loader[loader_defsize - 4] = char(ram_length & 0x00FF);
  287.                 loader[loader_defsize - 3] = char(ram_length >> 8);
  288.                 // Settings.Page
  289.                 loader[loader_defsize - 2] = char(Device->GetSlot(3)->Page->Number);
  290.  
  291.                 //
  292.                 unsigned char* pages_ram[1024];
  293.                 aint pages_len[1024];
  294.                 aint pages_start[1024];
  295.  
  296.                 // build pages table
  297.                 aint count = 0;
  298.                 for (aint i=0;i < Device->PagesCount;i++) {
  299.                         if (Device->GetSlot(2)->Page->Number != i && Device->GetSlot(1)->Page->Number != i) {
  300.                                 aint length = 0x4000;
  301.                                 length = remove_unused_space((unsigned char*)Device->GetPage(i)->RAM, length);
  302.                                 if (length > 0) {
  303.                                         pages_ram[count] = (unsigned char*)Device->GetPage(i)->RAM;
  304.                                         pages_start[count] = detect_ram_start(pages_ram[count], length);
  305.                                         pages_len[count] = length - pages_start[count];
  306.  
  307.                                         loader[loader_defsize + (count*5) + 0] = char(i);
  308.                                         loader[loader_defsize + (count*5) + 1] = char((pages_start[count] + 0xC000) & 0x00FF);
  309.                                         loader[loader_defsize + (count*5) + 2] = char((pages_start[count] + 0xC000) >> 8);
  310.                                         loader[loader_defsize + (count*5) + 3] = char(pages_len[count] & 0x00FF);
  311.                                         loader[loader_defsize + (count*5) + 4] = char(pages_len[count] >> 8);
  312.  
  313.                                         count++;
  314.                                 }
  315.                         }
  316.                 }
  317.  
  318.                 // Table_BlockList.Count
  319.                 loader[loader_defsize - 1] = char(count);
  320.  
  321.                 // Settings.LoadScreen
  322.                 loader[loader_defsize - 9] = char(has_screen_changes());
  323.  
  324.                 // write loader
  325.                 writecode(loader, loader_len, 0x5E00, true, fpout);
  326.  
  327.                 // write screen$
  328.                 if (loader[loader_defsize - 9]) {
  329.                         writecode((unsigned char*)Device->GetSlot(1)->Page->RAM, 6912, 0x4000, false, fpout);
  330.                 }
  331.  
  332.                 // write code blocks
  333.                 for (aint i=0;i < count;i++) {
  334.                         writecode(pages_ram[i] + pages_start[i], pages_len[i], 0xC000 + pages_start[i], false, fpout);
  335.                 }
  336.  
  337.                 // write main code block
  338.                 writecode(ram + ram_start, ram_length, 0x5E00 + ram_start, false, fpout);
  339.  
  340.                 free(ram);
  341.         }
  342.  
  343.         fclose(fpout);
  344.         return 1;
  345. }
  346.  
  347. void writenumber(unsigned int i, FILE *fp) {
  348.         int c;
  349.         c=i/10000;
  350.         i-=c*10000;
  351.         writebyte(c+48, fp);
  352.         c=i/1000;
  353.         i-=c*1000;
  354.         writebyte(c+48, fp);
  355.         c=i/100;
  356.         i-=c*100;
  357.         writebyte(c+48, fp);
  358.         c=i/10;
  359.         writebyte(c+48, fp);
  360.         i%=10;
  361.         writebyte(i+48, fp);
  362. }
  363.  
  364. void writeword(unsigned int i, FILE *fp) {
  365.         writebyte(i%256,fp);
  366.         writebyte(i/256,fp);
  367. }
  368.  
  369. void writebyte(unsigned char c, FILE *fp) {
  370.         fputc(c,fp);
  371.         parity^=c;
  372. }
  373.  
  374. void writeheader(unsigned char flag, const char *fname, unsigned short param1, unsigned short param2, unsigned short param3, FILE *fp) {
  375.         /* Write out the code header file */
  376.         writeword(19, fp);              /* Header len */
  377.         writebyte(0, fp);               /* Header is 0 */
  378.         parity = 0;
  379.         writebyte(flag, fp);    /* Filetype flag */
  380.  
  381.         const char *ptr = fname;
  382.         for (int i = 0; i < 10; i++) {
  383.                 if (*ptr) {
  384.                         writebyte(*ptr++, fp);
  385.                 } else {
  386.                         writebyte(' ', fp);
  387.                 }
  388.         }
  389.  
  390.         writeword(param1, fp);
  391.         writeword(param2, fp);
  392.         writeword(param3, fp);
  393.         writebyte(parity, fp);
  394. }
  395.  
  396. void writecode(unsigned char* block, aint length, unsigned short loadaddr, bool header, FILE *fp) {
  397.         if (header) {
  398.                 /* Filetype (3: Code) */
  399.                 writeheader(3, "loader", length, loadaddr, 0, fp);
  400.         }
  401.  
  402.         /* Now onto the data bit */
  403.         writeword(length + 2, fp);      /* Length of next block */
  404.         parity = 0;
  405.         writebyte(255, fp); /* Data... */
  406.         for (aint i = 0; i < length; i++) {
  407.                 writebyte(block[i], fp);
  408.         }
  409.         writebyte(parity, fp);
  410. }
  411.  
  412. void remove_basic_sp(unsigned char* ram) {
  413.         bool remove = true;
  414.         for (size_t i=0; i < sizeof(ZX_STACK_DATA);i++) {
  415.                 if (ZX_STACK_DATA[i] != ram[i]) {
  416.                         remove = false;
  417.                 }
  418.         }
  419.         if (remove) {
  420.                 for (size_t i=0; i < sizeof(ZX_STACK_DATA);i++) {
  421.                         ram[i] = 0;
  422.                 }
  423.         }
  424. }
  425.  
  426. void detect_vars_changes() {
  427.         unsigned char *psys = (unsigned char*)Device->GetSlot(1)->Page->RAM + 0x1C00;
  428.  
  429.         bool nobas48 = false;
  430.         for (size_t i=0; i < sizeof(ZX_SYSVARS_DATA);i++) {
  431.                 if (ZX_SYSVARS_DATA[i] != psys[i]) {
  432.                         nobas48 = true;
  433.                 }
  434.         }
  435.  
  436.         if (nobas48) {
  437.                 Warning("[SAVETAP] Tape file will not contains data from 0x5B00 to 0x5E00");
  438.         }
  439. }
  440.  
  441. bool has_screen_changes() {
  442.         unsigned char *pscr = (unsigned char*)Device->GetSlot(1)->Page->RAM;
  443.  
  444.         for (int i=0; i < 0x1800;i++) {
  445.                 if (0 != pscr[i]) {
  446.                         return true;
  447.                 }
  448.         }
  449.  
  450.         for (int i=0x1800; i < 0x1B00;i++) {
  451.                 if (0x38 != pscr[i]) {
  452.                         return true;
  453.                 }
  454.         }
  455.  
  456.         return false;
  457. }
  458.  
  459. aint remove_unused_space(unsigned char* ram, aint length) {
  460.         while (length > 0 && ram[length-1] == 0) {
  461.                 length--;
  462.         }
  463.  
  464.         return length;
  465. }
  466.  
  467. aint detect_ram_start(unsigned char* ram, aint length) {
  468.         aint start = 0;
  469.  
  470.         while (start < length && ram[start] == 0) {
  471.                 start++;
  472.         }
  473.  
  474.         return start;
  475. }
  476.  
  477. //eof io_tape.cpp
  478.