Subversion Repositories NedoOS

Rev

Rev 2259 | Details | Compare with Previous | Last modification | View Log

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