Subversion Repositories NedoOS

Rev

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

  1. // Z80 ciphers test framework
  2. // (c) 2019 lvd^mhm
  3.  
  4. /*
  5.     This file is part of Z80 ciphers test framework.
  6.  
  7.     Z80 ciphers test framework is free software:
  8.     you can redistribute it and/or modify it under the terms of
  9.     the GNU General Public License as published by
  10.     the Free Software Foundation, either version 3 of the License, or
  11.     (at your option) any later version.
  12.  
  13.     Z80 ciphers test framework is distributed in the hope that
  14.     it will be useful, but WITHOUT ANY WARRANTY; without even
  15.     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  16.     See the GNU General Public License for more details.
  17.  
  18.     You should have received a copy of the GNU General Public License
  19.     along with Z80 ciphers test framework.
  20.     If not, see <http://www.gnu.org/licenses/>.
  21. */
  22.  
  23. #include <stdint.h>
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <string.h>
  27.  
  28. #include "zetaZ80/Z80_lite.h"
  29.  
  30. #include "z80-wrap.h"
  31.  
  32.  
  33.  
  34. static uint8_t z80_filter_fetch_opcode(void * param, uint16_t address)
  35. {
  36.         struct z80_context * z80 = param;
  37.         uint8_t opcode = z80->z80_mem[address];
  38. /*
  39.         if( !z80->was_ed && opcode==0xED )
  40.         {
  41.                 z80->was_ed = 1;
  42.         }
  43.         else if( z80->was_ed )
  44.         {
  45.                 if( opcode==0xA9 )
  46.                 {
  47.                         fprintf(stderr,"\n<<<CPD detected!>>>>\n");
  48.                 }
  49.                 else if( opcode==0xB9 )
  50.                 {
  51.                         fprintf(stderr,"\n<<<CPDR detected!>>>>\n");
  52.                 }
  53.  
  54.                 if( opcode==0xA9 || opcode==0xB9 )
  55.                 {
  56.                         fprintf(stderr,"<<< MEMPTR=%04x >>>\n",z80->z80.memptr);
  57.                         fprintf(stderr,"<<<     AF=%04x >>>\n",z80->z80.af);
  58.                         fprintf(stderr,"<<<     BC=%04x >>>\n",z80->z80.bc);
  59.                         fprintf(stderr,"<<<     DE=%04x >>>\n",z80->z80.de);
  60.                         fprintf(stderr,"<<<     HL=%04x >>>\n",z80->z80.hl);
  61.                         fprintf(stderr,"<<<     SP=%04x >>>\n",z80->z80.sp);
  62.                         fprintf(stderr,"<<<     PC=%04x >>>\n",z80->z80.pc);
  63.                 }
  64.  
  65.                 z80->was_ed = 0;
  66.         }
  67. */
  68.         return opcode;
  69. }
  70.  
  71. static uint8_t z80_filter_zx_api(void * param, uint16_t address)
  72. {
  73.         struct z80_context * z80 = param;
  74.  
  75.         if( address==0x1601 ) // CHAN-OPEN (ignore)
  76.         {
  77.                 return 0xC9;
  78.         }
  79.         else if( address==0x0010 ) // RST 0x10 (print character)
  80.         {
  81.                 uint8_t c = ((z80->z80.af)>>8)&0xFF;
  82.  
  83.                 if( z80->was_23 ) // skip 2 bytes after 23
  84.                 {
  85.                         if( z80->was_23==2 )
  86.                         {
  87.                                 fprintf(stdout,"\033[%dG",c);
  88.                         }
  89.  
  90.                         z80->was_23--;
  91.                 }
  92.                 else if( c==13 )
  93.                 {
  94.                         fprintf(stdout,"\n");
  95.                 }
  96.                 else if( c==127 ) // skip
  97.                 {
  98.                 }
  99.                 else if( c==23 ) // skip following 2 bytes
  100.                 {
  101.                         z80->was_23=2;
  102.                 }
  103.                 else
  104.                 {
  105.                         fprintf(stdout,"%c",c);
  106.                         fflush(stdout);
  107.                 }
  108.  
  109.                 return 0xC9;
  110.         }
  111.         else if( address<0x4000 ) // catch all other ROM accesses
  112.         {
  113.                 fprintf(stderr,"Accessed addr %04x! [sp]=%04x\n",address,*((uint16_t *)&z80->z80_mem[z80->z80.sp]));
  114.                 exit(1);
  115.         }
  116.  
  117.         return z80_filter_fetch_opcode(param, address);
  118. }
  119.  
  120. static uint8_t z80_filter_nedoos_api(void * param, uint16_t address)
  121. {
  122.         struct z80_context * z80 = param;
  123.  
  124.         if( address==0 )
  125.         {
  126.                 fprintf(stdout,"\n<<<Finished in %ld clocks!>>>\n",z80->z80.cycles);
  127.                 exit(0);
  128.         }
  129.         else if( address==5 )
  130.         {
  131.                 uint8_t c = (z80->z80.bc)&0xFF;
  132.  
  133.                 if( c==0xD3 // GETSTDINOUT
  134.                  || c==0xFF // YIELDKEEP
  135.                   )
  136.                 {
  137.                         return 0xC9; // just ignore
  138.                 }
  139.                 else if( c==0x49 ) // WRITEHANDLE
  140.                 { // in:B  - handle (ignore)
  141.                   // in:DE - buffer
  142.                   // in:HL - bytes to write
  143.                   // out:HL - actually written
  144.                   // out:A  - error if nonzero
  145.                        
  146.                         uint16_t ptr = z80->z80.de;
  147.                         uint16_t ctr = z80->z80.hl;
  148.  
  149.                         while( ctr-- )
  150.                         {
  151.                                 fprintf(stdout,"%c",z80->z80_mem[ptr++]);
  152.                         }
  153.                         if( z80->z80.hl ) fflush(stdout);
  154.  
  155.                         // HL unchanged
  156.                         z80->z80.af &= 0x00FF;
  157.                        
  158.                         return 0xC9;
  159.                 }
  160.                 else
  161.                 {
  162.                         fprintf(stderr,"\n<<unknown BDOS call: c=%02x!>>\n",c);
  163.                         exit(1);
  164.                 }
  165.         }
  166.  
  167.         return z80_filter_fetch_opcode(param, address);
  168. }
  169.  
  170. static uint8_t z80_filter_cpm_api(void * param, uint16_t address)
  171. {
  172.         struct z80_context * z80 = param;
  173.  
  174.         if( address==0 )
  175.         {
  176.                 fprintf(stdout,"\n<<<Finished in %ld clocks!>>>\n",z80->z80.cycles);
  177.                 exit(0);
  178.         }
  179.         else if( address==5 )
  180.         {
  181.                 uint8_t c = (z80->z80.bc)&0xFF;
  182.  
  183.                 if( c==2 ) // print char in e
  184.                 {
  185.                         fprintf(stdout,"%c",(z80->z80.de)&0xFF);
  186.                         fflush(stdout);
  187.                 }
  188.                 else if( c==9 ) // print string pointed to by de
  189.                 {
  190.                         uint16_t ptr = z80->z80.de;
  191.                         uint8_t chr;
  192.  
  193.                         while( (chr=z80->z80_mem[ptr++]) != '$' )
  194.                         {
  195.                                 fprintf(stdout,"%c",chr);
  196.                         }
  197.                         fflush(stdout);
  198.                 }
  199.                 else
  200.                 {
  201.                         fprintf(stderr,"\n<<<Unknown CP/M API call: C=%02x>>>\n", c);
  202.                         exit(1);
  203.                 }
  204.  
  205.                 return 0xC9;
  206.         }
  207.  
  208.         return z80_filter_fetch_opcode(param, address);
  209. }
  210.  
  211. static uint8_t z80_rd(void * param, uint16_t address)
  212. {
  213.         struct z80_context * z80 = param;
  214.  
  215.         return z80->z80_mem[address];
  216. }
  217.  
  218. static void    z80_zx_wr(void * param, uint16_t address, uint8_t data)
  219. {
  220.         struct z80_context * z80 = param;
  221.  
  222.         if( address>=0x4000 ) z80->z80_mem[address] = data;
  223. }
  224.  
  225. static void    z80_wr(void * param, uint16_t address, uint8_t data)
  226. {
  227.         struct z80_context * z80 = param;
  228.  
  229.         z80->z80_mem[address] = data;
  230. }
  231.  
  232. static void    z80_hlt(void * param, uint8_t state)
  233. {
  234.         struct z80_context * z80 = param;
  235.  
  236.         z80_break(&z80->z80);
  237. }
  238.  
  239. static void z80_out(void * param, uint8_t state)
  240. {
  241.         // ignore
  242. }
  243.  
  244. static uint8_t z80_in(void * param, uint16_t address)
  245. {
  246.         struct z80_context * z80 = param;
  247.  
  248.         return 0xBF;
  249. }
  250.  
  251.  
  252.  
  253. struct z80_context * z80_init(char * filename, int sys_type)
  254. {
  255.         // allocate structure for z80 context and associated data
  256.         //
  257.  
  258.         struct z80_context * z80 = malloc(sizeof(struct z80_context));
  259.         //
  260.         if( !z80 )
  261.         {
  262.                 fprintf(stderr,"%s: %d, %s: can't allocate memory for struct z80_context!\n",__FILE__,__LINE__,__func__);
  263.                 exit(1);
  264.         }
  265.  
  266.         // clear Z80 memory
  267.         memset(z80->z80_mem,0,65536);
  268.  
  269.         // load Z80 .com binary
  270.         if( filename )
  271.         {
  272.                 size_t load_address = (sys_type==SYS_ZX) ? 0x8000 : 0x0100;
  273.  
  274.  
  275.                 FILE * f = fopen(filename,"rb");
  276.                 if( !f )
  277.                 {
  278.                         fprintf(stderr,"%s: %d, %s: can't open Z80 binary file <%s>!\n",__FILE__,__LINE__,__FUNCTION__,filename);
  279.                         exit(1);
  280.                 }
  281.                 //
  282.                 size_t read=fread(z80->z80_mem+load_address,1,65536-load_address,f);
  283.                 off_t o=ftello(f);
  284.                 int seek=fseeko(f,0,SEEK_END);
  285.                 off_t e=ftello(f);
  286.                 if( seek || o!=e || read!=e || !(0<o && o<=(65536-load_address)) )
  287.                 {
  288.                         fprintf(stderr,"%s: %d, %s: can't read Z80 .com file <%s>!\n",__FILE__,__LINE__,__FUNCTION__,filename);
  289.                         exit(1);
  290.                 }
  291.                 fclose(f);
  292.         }
  293.  
  294.         if( sys_type==SYS_ZX ) // load ROM
  295.         {
  296.                 FILE * f = fopen("1982.rom","rb");
  297.                 if( !f )
  298.                 {
  299.                         fprintf(stderr,"%s: %d, %s: can't open <1982.rom>!\n",__FILE__,__LINE__,__FUNCTION__);
  300.                         exit(1);
  301.                 }
  302.                 //
  303.                 size_t read=fread(z80->z80_mem,1,16384,f);
  304.                 off_t o=ftello(f);
  305.                 int seek=fseeko(f,0,SEEK_END);
  306.                 off_t e=ftello(f);
  307.                 if( seek || o!=e || read!=e || o!=16384 )
  308.                 {
  309.                         fprintf(stderr,"%s: %d, %s: can't read <1982.rom>!\n",__FILE__,__LINE__,__FUNCTION__);
  310.                         exit(1);
  311.                 }
  312.                 fclose(f);
  313.         }
  314.  
  315.         // init cp/m stack value
  316.         if( sys_type==SYS_CPM )
  317.         {
  318.                 z80->z80_mem[6] = 0x00;
  319.                 z80->z80_mem[7] = 0x40;
  320.         }
  321.        
  322.         // start address
  323.         z80->start_address = (sys_type==SYS_ZX) ? 0x8000 : 0x0100;
  324.  
  325.         // start SP
  326.         z80->start_sp = (sys_type==SYS_ZX) ? 0x8000 : 0x4000;
  327.  
  328.         // init callbacks
  329.         z80->z80.context   = (void *)z80;
  330.  
  331.         z80->z80.nmia      = NULL;
  332.         z80->z80.inta      = NULL;
  333.         z80->z80.int_fetch = NULL;
  334.         z80->z80.ld_i_a    = NULL;
  335.         z80->z80.ld_r_a    = NULL;
  336.         z80->z80.reti      = NULL;
  337.         z80->z80.retn      = NULL;
  338.         z80->z80.illegal   = NULL;
  339.  
  340.         z80->z80.fetch_opcode = (sys_type==SYS_ZX    ) ? (&z80_filter_zx_api)     :
  341.                                 (sys_type==SYS_NEDOOS) ? (&z80_filter_nedoos_api) :
  342.                                 (sys_type==SYS_CPM   ) ? (&z80_filter_cpm_api)    : NULL;
  343.  
  344.         z80->z80.fetch        = &z80_rd;
  345.         z80->z80.read         = &z80_rd;
  346.         z80->z80.nop          = &z80_rd;
  347.  
  348.         z80->z80.write     = (sys_type==SYS_ZX) ? &z80_zx_wr : &z80_wr;
  349.  
  350.         z80->z80.hook      = NULL;
  351.  
  352.         z80->z80.in        = &z80_in;
  353.         z80->z80.out       = &z80_out;
  354.  
  355.         z80->z80.halt      = &z80_hlt;
  356.  
  357.  
  358.         return z80;
  359. }
  360.  
  361.  
  362.  
  363.  
  364. size_t z80_exec(struct z80_context * z80, size_t max_clocks)
  365. {
  366.         z80->was_ed = 0;
  367.  
  368.         z80_power(&z80->z80,1);
  369.  
  370.         z80->z80.pc = z80->start_address;
  371.         z80->z80.sp = z80->start_sp;
  372.        
  373.         size_t clocks = z80_execute(&z80->z80, max_clocks);
  374.  
  375.  
  376.         if( !z80->z80.halt_line )
  377.                 return 0;
  378.        
  379.         return clocks;
  380. }
  381.  
  382.  
  383.  
  384.  
  385.  
  386. uint8_t  z80_rdbyte(struct z80_context * z80, uint16_t addr)
  387. {
  388.         return z80->z80_mem[addr];
  389. }
  390.  
  391. uint16_t z80_rdword_le(struct z80_context * z80, uint16_t addr)
  392. {
  393.         return (((uint16_t)z80_rdbyte(z80,addr+0)) & 0x00FF) |
  394.                (((uint16_t)z80_rdbyte(z80,addr+1)) << 8    ) ;
  395. }
  396.  
  397. uint32_t z80_rdlong_le(struct z80_context * z80, uint16_t addr)
  398. {
  399.         return (((uint32_t)z80_rdword_le(z80,addr+0)) & 0x0000FFFF) |
  400.                (((uint32_t)z80_rdword_le(z80,addr+2)) << 16       ) ;
  401. }
  402.  
  403. uint64_t z80_rdocta_le(struct z80_context * z80, uint16_t addr)
  404. {
  405.         return (((uint64_t)z80_rdlong_le(z80,addr+0)) & 0xFFFFFFFFull) |
  406.                (((uint64_t)z80_rdlong_le(z80,addr+4)) << 32          ) ;
  407. }
  408.  
  409. void z80_wrbyte(struct z80_context * z80, uint16_t addr, uint8_t  data)
  410. {
  411.         z80->z80_mem[addr]=data;
  412. }
  413.  
  414. void z80_wrword_le(struct z80_context * z80, uint16_t addr, uint16_t data)
  415. {
  416.         z80_wrbyte(z80,addr+0,data & 0x00FF);
  417.         z80_wrbyte(z80,addr+1,data >> 8    );
  418. }
  419.  
  420. void z80_wrlong_le(struct z80_context * z80, uint16_t addr, uint32_t data)
  421. {
  422.         z80_wrword_le(z80,addr+0,data & 0x0000FFFF);
  423.         z80_wrword_le(z80,addr+2,data >> 16       );
  424. }
  425.  
  426. void z80_wrocta_le(struct z80_context * z80, uint16_t addr, uint64_t data)
  427. {
  428.         z80_wrlong_le(z80,addr+0,data & 0xFFFFFFFFull);
  429.         z80_wrlong_le(z80,addr+4,data >> 32          );
  430. }
  431.  
  432.