From
SMT
→
To
All
22 January 2006
Hello SMT
if you make a completely universal kernel, you need to provide for an increase in the current
time and in functions of working with memory/ports - in some models, and at least in
original 48/128, generated by WAIT when accessing port #FE and half
memory pages. the processor and devices like
Scorpio PC keyboard controller
From
SMT
→
To
All
22 January 2006
Hello, boo_boo
boo> , in which I need to inherit from the Z80 class, I can’t
boo> submit
Well, you can inherit by redefining the virtual functions for reading ports/memory, but
this does not exempt the call via a pointer. you should not inherit from the class
Z80, but do something like this:
┌─- CODE ───
CUniversalZ80WithoutMemPorts MainZ80;
CUniversalZ80WithoutMemPorts MainZ80Dbg;
CUniversalZ80WithoutMemPorts gsZ80;
└── CODE ───
such nuclei can easily be made as many as necessary, and everything that relates to
memory/ports will be inlined. In principle, unreal has 3 cores. I don't know if it's worth it
to increase speed, in some cases increase the size so much
the final exe. although, if now emulators even write in toad, the speed
you can donate
boo> where can I read about this cache? I have little idea who
boo> he is like that
black crow magazines#3, dejavu#7. this is static RAM 2-16k, solderable
parallel to the ROM. there is a small circuit that turns it on instead of ROM
(for example, instead of TR-DOS, allowing the program in this cache to immediately access
the entire 48th memory, and to the drive ports). if the RAM is small (2-8k), then
the senior address lines do not go anywhere, so the entry to address #0111"will write" in #0911,#1111,#1911,#2111,#2911,#3111,#3911...
SMT> write to the port with a timestamp somewhere between start and
SMT> end of command
boo> a few words about how this is done in the US?
The Z80 core increases the clock counter cpu.t by the required amount, calls the function
writes to the port (which reads this counter), and again increases cpu.t, in total
these increments will give the command execution time. if, as you want, absolutely
to abandon global variables, you will have to drag these timestamps like
parameters:
for example, in void step(Z80 *cpu, int64 &tick) pass the start time, then,
for example, in the OTIR command call void port_out(cpu->bc, read_mem(cpu->hl),
tick+16), and then increase tick by 21
From
SMT
→
To
All
22 January 2006
Hello, boo_boo
why yours? if TR-DOS was rather weak, then for the Z80 it is easier to correct what
is in the glitch
why are there only 3 16k arrays and not 4?
Z80 cores in bulk. I can suggest looking for the Z80 kernel just under gcc/gpl from (C)
Marat Fayzullin (author of the MSX-2 emulator), it also has a dizasm (if you can’t find it,
there is a RAR archive - 19k)
If you are not looking for speed, any implementation will do. and if you chase, then
you need to build memory and port read/write functions directly into the emulation code
Z80 instructions (without calling through the pointer), and other necessities like all sorts
breakpoints for different events
You can design it modularly by writing these functions marked inline and including
Z80 kernel, or more beautifully - as a template class, then it is passed to the constructor
class that reads memory/ports, eats inline functions
in fact, the Z80 is inextricably linked to the emulation cycle. because INT
processed depending on whether there was a previous one. EI team
for Scorpio with professional ROM, ROM pages switch when reading certain
addresses. Pentagon cache 2-8K has pages less than 16K, and writes
in one area should affect the mirror others (implemented in Z80S -
there in the kernel the page size is not 16K, but 2K). accurate emulation of border effects
requires writing to a port with a timestamp somewhere between the beginning and the endcommands, and the shift depends on the type of command: outi, out (#FE),a or out (c),d
these 3 examples are not taken into account by the proposed API
In general, untying the general from time to time within the frame is a good idea. it's a pity that
I didn’t notice it earlier (probably I noticed __int64 too late). everything in real
time turned out terribly confusing
From
Stanislav Lomakin
→
To
All
22 January 2006
Hello, All
I’m thinking of writing a separate z80 emulation module, in pure C, so that with half a kick
inserted anywhere - library and h-file. I'll probably use the code as a basis
from FUSE.. or US...
the question is how to make an API, the requirements are the ability to create several
processors, no exported variables, only functions, and support
all the features, of course :)
I jotted down something like this:
┌─- CODE ───
/*processor - flooded from FUSE*/
typedef struct {
regpair af,bc,de,hl;
regpair af_,bc_,de_,hl_;
regpair ix,iy;
byte i;
word r;
byte r7; /* The high bit of the R register */
regpair sp,pc;
byte iff1, iff2, im;
int halted;
} Z80;
/*creation and initialization of the processor.
page1/2/3 -- pointers to arrays (16K long),
which will be used as memory pages*/
Z80 *z80_create(void *page1, void *page2, void *page3);
/*destroying the processor - I indulge my passion for destruction ;) */
void z80_destroy(Z80 *cpu);
/*replacement of one of 3 memory pages - for things like
switching 128k pages, etc.*/
void z80_set_mempage(Z80 *cpu, int page_num, void *page);
/*execute the next command, returns the amount spent
number of bars*/
int z80_step(Z80 *cpu);
/*setting the callback function to read from the port*/
void z80_set_pread_cb(Z80 *cpu, z80_pread_cb cb_fn);
/*setting the callback to write to the port*/void z80_set_pwrite_cb(Z80 *cpu, z80_pwrite_cb cb_fn);
/*setting the callback to read from memory*/
void z80_set_mread_cb(Z80 *cpu, z80_mread_cb cb_fn);
/*setting the callback to write to memory*/
void z80_set_mwrite_cb(Z80 *cpu, z80_mwrite_cb cb_fn);
/*interrupt*/
void z80_int(Z80 *cpu);
/*non-maskable interrupt*/
void z80_nmi(Z80 *cpu);
/*reset*/
void z80_reset(Z80 *cpu)
/*functions for getting register values - so
don’t get tied up in the fields of the Z80 struct*/
too lazy to write)
└── CODE ───
From
Stanislav Lomakin
→
To
All
22 January 2006
Hello SMT
SMT> why have your own? if TR-DOS was weak, then for the Z80 it’s easier to fix it
SMT> what is in the glitch
SMT>
It’s like I’m looking at the source code of a glitch, and I give up - it’s all in one piece
in a ball... I want it to be like in life - the z80 doesn’t know what’s inside the VG, and
on the contrary, they simply communicate through some interface. in general, IMHO, this is
separation will also save me time (the code is easier to navigate and debug,
when everything is in order), and people will find it useful.
SMT> why are there only 3 16k arrays and not 4?
SMT>
yeah, 4 of them, buggy :)
SMT> Z80 cores in bulk
SMT>
I have not found any practically that does not require intervention in the code in order
use it... and if so, then at the same time you can shovel everything a little and your
Make an API. Fayzulla emulsion is good, but does not allow more than one
create a processor, and this may be useful (GS, etc.)
I don’t want to chase speed; taking into account the power of modern computers, the costs for
calling a function through a pointer is not scary :)
On the one hand, you can make API classes, but on the other hand, pure C is more universal,
but I can’t find a situation in which I need to inherit from the Z80 class
imagine :oSMT> in fact, the Z80 is inextricably linked to the emulation cycle. because
SMT> INT is processed depending on whether there was a previous one. EI team
SMT>
You can check the box for this case...
SMT> for Scorpio with professional ROM, ROM pages switch when read
SMT> specific addresses.
SMT>
Well, you can track this in the memory reading callback and change it
page...
SMT> Pentagon cache 2-8K has pages less than 16K, and writes
SMT> in one area should affect the mirror others
SMT> (implemented in Z80S - there in the kernel the page size is not 16K, but 2K).
SMT>
where can I read about this very cache? I have no idea who he is
:(
SMT> accurate emulation of border effects requires writing to port c
SMT> timestamp somewhere between the beginning and end of the command, with a shift
SMT> depends on the command type: outi, out (#FE),a or out (c),d
SMT>
Can you say a few words about how this is done in the US?
From
Stanislav Lomakin
→
To
All
23 January 2006
Hello SMT
I'm delusional about memory pages - the z80 doesn't know any pages, but has them
It's already a memory controller, and its emulation is a separate issue.
so I think it’s enough to set callbacks to read memory (returns
byte to address) and to write (set accordingly)
SMT> Z80 core increases the cpu.t clock counter by the required amount
SMT> calls the port write function (which reads this counter), and again
SMT> increases cpu.t, in total these increments will give the execution time
SMT> commands. if, as you want, you completely abandon global
SMT> variables, you will have to drag these timestamps as parameters:
SMT> for example, in void step(Z80 *cpu, int64 &tick) pass the start time
SMT> then, for example, in the OTIR command call void port_out(cpu->bc,
SMT> read_mem(cpu->hl), tick+16), and then increase tick by 21
yeah... hmmm... and if so: add another callback that will be called
at every beat. organize a delay in it, launch personnel
sync pulse, INT.... In general, do everything there that has to do with timing.
And WAIT from memory and #FE are also arranged externally, intercepting these operations in
callbacks for accessing memory/port.
From
SMT
→
To
All
23 January 2006
Hello, boo_boo
with a clock-by-cycle callback it will be 10 times slower. now, of course, is not the time
P-133, so it doesn't matter. but if you transfer from unreal AY and ULA with their decoupling
from the Z80, from each other and from other devices, you will have to switch everything
super-perverted and make, as for the Z80, a step function that emulates 1
clock of the device and call it from such a callback
I have now come up with an independent interface for AY: the input is an array of records to the port
(register number, value, AY clock), and the last emulation clock (in case
There was no recording, but we need to get the sound). the output is the number of complete samples,
issued by AY before the required clock cycle and an array of the actual samples. defiant
The function must provide a buffer of sufficient size. thus,
losses from frequent switching Z80/ULA/AY are minimized, you can also write
such a buffer directly into a PSG file, or by writing only the last register values to
frame and passed through LHA to a VTX file. I like it better than beat by beat
emulation?
oh!, in the next versions of unreal I’ll do this - there should be an increase in
performance by minimizing data replacement to the L1 code cache and
sequential access to arrays. At the same time, an analiasing FIR filter can be
will write more transparently, almost “on the forehead”
From
Stanislav Lomakin
→
To
All
23 January 2006
Hello SMT
SMT> has now come up with an independent interface for AY: the input is an array of records
SMT> to port (register number, value, AY clock), and the last emulation clock
SMT> (in case there was no recording, but you need to get sound). at the output -
SMT> number of complete samples issued by AY before the required clock and array
SMT> samples themselves. the calling function must provide a buffer
SMT> is of sufficient size. thus, losses from frequent
SMT> switching Z80/ULA/AY, you can also write such a buffer directly to
SMT> PSG file, or by writing only the last register values in the frame and
SMT> driven through LHA into a VTX file. I like it better than beat by beat
SMT> emulation?
SMT>
that is, accumulate calls to AY ports, and then feed such a function,
getting a piece of sound from her... very nice :)
but then there will be some lag behind the AY from the Z80 - what to do if the encoder
wants to read the register rather than write it?
From
Stanislav Lomakin
→
To
All
24 January 2006
Hello SMT
SMT> ah, this is a small thing. store an array of 16 registers, they do not change with
SMT> side of AY itself
ah, cool :)
another API option for z80, taking into account the shortcomings of the previous one:
┌─- CODE ───
enum Z80_REG_T
{regAF,regBC,regDE,regHL,regAF_,regBC_,regDE_,regHL_,regIX,regIY,regPC,regSP,re
gIR,regIM/*0,1 or 2*/,regIFF1,regIFF2};
typedef void (*z80_tstate_cb)();
/*the next 4 callbacks take the tick number in the step as the first argument,
which input/output is made*/
typedef unsigned char (*z80_pread_cb)(unsigned char t_state, unsigned port);
typedef void (*z80_pwrite_cb)(unsigned char t_state, unsigned port, unsigned
char value);
typedef unsigned char (*z80_mread_cb)(unsigned char t_state, unsigned addr);
typedef void (*z80_mwrite_cb)(unsigned char t_state, unsigned addr, unsigned
char value);
struct _z80_cpu_context;
typedef struct _z80_cpu_context Z80;
/*creation and initialization of the processor.*/
Z80 *z80_create();
/*destroying the processor - I indulge my passion for destruction ;) */
void z80_destroy(Z80 *cpu);
/*execute the next command, returns the number of cycles spent*/
int z80_step(Z80 *cpu);
/*setting a callback that will be called at every emulation clock*/
void z80_set_tstate_callback(Z80 *cpu, z80_tstate_cb cb_fn);
/*setting the callback function to read from the port*/void z80_set_pread_cb(Z80 *cpu, z80_pread_cb cb_fn);
/*setting the callback to write to the port*/
void z80_set_pwrite_cb(Z80 *cpu, z80_pwrite_cb cb_fn);
/*setting the callback to read from memory*/
void z80_set_mread_cb(Z80 *cpu, z80_mread_cb cb_fn);
/*setting the callback to write to memory*/
void z80_set_mwrite_cb(Z80 *cpu, z80_mwrite_cb cb_fn);
/*interrupt, second argument - opcode for IM0%)*/
void z80_int(Z80 *cpu, unsigned char op);
/*non-maskable interrupt*/
void z80_nmi(Z80 *cpu);
/*generation of w_states WAIT cycles. (w_states will be called once
clock callback)
for use in memory access callbacks and
ports*/
void z80_w_states(Z80 *cpu, unsigned w_states);
/*reset*/
void z80_reset(Z80 *cpu)
/*function to get the register value*/
unsigned z80_get_reg(Z80 *cpu, enum Z80_REG_T reg);
/*function for setting the register value*/
unsigned z80_set_reg(Z80 *cpu, enum Z80_REG_T reg, unsigned value);
/*returns 1 if z80 is waiting at halt*/
int z80_is_halted(Z80 *cpu);
└── CODE ───