Alex Badea (8):
upd_fdc: implement Terminal Count support
debugger: add support for setting IM and IFFs
gtk debugger: use MEMORY_PAGE_SIZE instead of hard-coded 4k
disk: allow reading mgt layouts of 80x16x256 and 40x16x256
HACK disk: disable size checking when writing .mgt images
HACK disk: add a bunch of fprintf() debug logging
memory: change page size from 4k to 1k
HACK if1: add HC uPD disk interface support
fuse/debugger/command.c | 18 +++
fuse/debugger/commandl.l | 3 +
fuse/memory.h | 2 +-
fuse/peripherals/disk/disk.c | 11 +-
fuse/peripherals/disk/fdd.c | 1 +
fuse/peripherals/disk/upd_fdc.c | 84 ++++++++++---
fuse/peripherals/disk/upd_fdc.h | 2 +
fuse/peripherals/if1.c | 250 ++++++++++++++++++++++++++++++++++++++-
fuse/ui/gtk/debugger.c | 2 +-
9 files changed, 349 insertions(+), 24 deletions(-)
parent 88be0872bb7a7a30c7697ccd0da8add02c859f79
Fix regression in GTK UI pause menu from r4685 (bug #3523741) (Sergio).
git-svn-id: https://fuse-emulator.svn.sourceforge.net/svnroot/fuse-emulator/trunk@4701 6c7d1b9a-d430-0410-8293-a2b96dacb39b
commit b025baa9e4e91ab1309e9904ee2424f7e30531a5
Author: Alex Badea <abadea@ixiacom.com>
Date: Wed May 23 18:59:51 2012 +0300
upd_fdc: implement Terminal Count support
Add an API which allows signalling of the TC input to the FDC. If TC
is asserted, store this in a flag and use it to disable sending further
result data for reads, or to fill in zeroes for writes. Also disable
setting end-of-cylinder if TC is asserted.
Since the host usually asserts TC after reading/write the last data byte
to/from the data port, the start_{read,write}* functions are deferred
to an event, instead of being called directly from port I/O. This gives
the host some time to assert TC.
---
fuse/peripherals/disk/upd_fdc.c | 44 +++++++++++++++++++++++++++------------
fuse/peripherals/disk/upd_fdc.h | 2 ++
2 files changed, 33 insertions(+), 13 deletions(-)
diff --git a/fuse/peripherals/disk/upd_fdc.c b/fuse/peripherals/disk/upd_fdc.c
index 253bc10..ca6db57 100644
--- a/fuse/peripherals/disk/upd_fdc.c
+++ b/fuse/peripherals/disk/upd_fdc.c
@@ -117,6 +117,7 @@ cmd_identify( upd_fdc *f )
break;
r++;
}
+ f->tc = 0;
f->mt = f->command_register >> 7; /* Multi track READ/WRITE */
f->mf = ( f->command_register >> 6 ) & 0x01; /* MFM format */
f->sk = ( f->command_register >> 5 ) & 0x01; /* Skip DELETED/NONDELETED sectors */
@@ -148,6 +149,7 @@ upd_fdc_master_reset( upd_fdc *f )
f->cycle = 0;
f->last_sector_read = 0;
f->read_id = 0;
+ f->tc = 0;
/* preserve disabled state of speedlock_hack */
if( f->speedlock != -1 ) f->speedlock = 0;
}
@@ -571,7 +573,7 @@ start_read_data( upd_fdc *f )
skip_deleted_sector:
multi_track_next:
if( f->first_rw || f->read_id ||
- f->data_register[5] > f->data_register[3] ) {
+ (!f->tc && f->data_register[5] > f->data_register[3]) ) {
if( !f->read_id ) {
if( !f->first_rw )
f->data_register[3]++;
@@ -630,7 +632,7 @@ abort_read_data:
* 3. terminal count is not received
* note: in +3 uPD765 never got TC
*/
- if( !f->status_register[0] && !f->status_register[1] ) {
+ if( !f->status_register[0] && !f->status_register[1] && !f->tc ) {
f->status_register[0] |= UPD_FDC_ST0_INT_ABNORM;
f->status_register[1] |= UPD_FDC_ST1_EOF_CYLINDER;
}
@@ -664,7 +666,7 @@ start_write_data( upd_fdc *f )
multi_track_next:
if( f->first_rw || f->read_id ||
- f->data_register[5] > f->data_register[3] ) {
+ (!f->tc && f->data_register[5] > f->data_register[3]) ) {
if( !f->read_id ) {
if( !f->first_rw )
f->data_register[3]++;
@@ -731,8 +733,10 @@ abort_write_data:
* 3. terminal count is not received
* note: in +3 uPD765 never got TC
*/
- f->status_register[0] |= UPD_FDC_ST0_INT_ABNORM;
- f->status_register[1] |= UPD_FDC_ST1_EOF_CYLINDER;
+ if( !f->tc ) {
+ f->status_register[0] |= UPD_FDC_ST0_INT_ABNORM;
+ f->status_register[1] |= UPD_FDC_ST1_EOF_CYLINDER;
+ }
f->main_status &= ~UPD_FDC_MAIN_EXECUTION;
f->intrq = UPD_INTRQ_RESULT;
cmd_result( f );
@@ -747,6 +751,14 @@ abort_write_data:
}
static void
+start_readwrite_data_later( upd_fdc *f )
+{
+ event_add_with_data( tstates +
+ machine_current->timings.processor_speed / 1000,
+ fdc_event, f );
+}
+
+static void
start_write_id( upd_fdc *f )
{
int i;
@@ -894,7 +906,7 @@ upd_fdc_read_data( upd_fdc *f )
/* EOSpeedlock hack */
r = d->fdd.data & 0xff;
- if( f->data_offset == f->rlen ) { /* send only rlen byte to host */
+ if( f->data_offset == f->rlen || f->tc ) { /* send only rlen byte to host */
while( f->data_offset < f->sector_length ) {
fdd_read_write_data( &d->fdd, FDD_READ ); crc_add( f, d );
f->data_offset++;
@@ -916,14 +928,14 @@ upd_fdc_read_data( upd_fdc *f )
if( f->cmd->id == UPD_CMD_READ_DATA ) {
if( f->ddam != f->del_data ) { /* we read a not 'wanted' sector... so */
- if( f->data_register[5] > f->data_register[3] ) /* if we want to read more... */
+ if( !f->tc && f->data_register[5] > f->data_register[3] ) /* if we want to read more... */
f->status_register[0] |= UPD_FDC_ST0_INT_ABNORM;
cmd_result( f ); /* set up result phase */
return r;
}
f->rev = 2;
f->main_status &= ~UPD_FDC_MAIN_DATAREQ;
- start_read_data( f );
+ start_readwrite_data_later( f );
} else { /* READ DIAG */
f->data_register[3]++; /*FIXME ??? */
f->data_register[5]--;
@@ -932,7 +944,7 @@ upd_fdc_read_data( upd_fdc *f )
return r;
}
f->main_status &= ~UPD_FDC_MAIN_DATAREQ;
- start_read_diag( f );
+ start_readwrite_data_later( f );
}
}
return r;
@@ -1063,7 +1075,7 @@ upd_fdc_write_data( upd_fdc *f, libspectrum_byte data )
d->fdd.data = data;
fdd_read_write_data( &d->fdd, FDD_WRITE ); crc_add( f, d );
- if( f->data_offset == f->rlen ) { /* read only rlen byte from host */
+ if( f->data_offset == f->rlen || f->tc ) { /* read only rlen byte from host */
d->fdd.data = 0x00;
while( f->data_offset < f->sector_length ) { /* fill with 0x00 */
fdd_read_write_data( &d->fdd, FDD_READ ); crc_add( f, d );
@@ -1076,7 +1088,7 @@ upd_fdc_write_data( upd_fdc *f, libspectrum_byte data )
d->fdd.data = f->crc & 0xff;
fdd_read_write_data( &d->fdd, FDD_WRITE ); /* write crc2 */
f->main_status &= ~UPD_FDC_MAIN_DATAREQ;
- start_write_data( f );
+ start_readwrite_data_later( f );
}
return;
} else { /* SCAN */
@@ -1104,7 +1116,7 @@ upd_fdc_write_data( upd_fdc *f, libspectrum_byte data )
f->data_register[3] += f->data_register[7]; /*FIXME what about STP>2 or STP<1 */
if( f->ddam != f->del_data ) { /* we read a not 'wanted' sector... so */
- if( f->data_register[5] >= f->data_register[3] ) /* if we want to read more... */
+ if( !f->tc && f->data_register[5] >= f->data_register[3] ) /* if we want to read more... */
f->status_register[0] |= UPD_FDC_ST0_INT_ABNORM;
cmd_result( f ); /* set up result phase */
return;
@@ -1116,7 +1128,7 @@ upd_fdc_write_data( upd_fdc *f, libspectrum_byte data )
}
f->rev = 2;
f->main_status &= ~UPD_FDC_MAIN_DATAREQ;
- start_read_data( f );
+ start_readwrite_data_later( f );
}
return;
}
@@ -1345,3 +1357,9 @@ upd_fdc_write_data( upd_fdc *f, libspectrum_byte data )
f->cycle++;
}
}
+
+void upd_fdc_tc( upd_fdc *f, int tc )
+{
+ if (tc > 0)
+ f->tc = 1;
+}
diff --git a/fuse/peripherals/disk/upd_fdc.h b/fuse/peripherals/disk/upd_fdc.h
index c5ba2aa..400dd38 100644
--- a/fuse/peripherals/disk/upd_fdc.h
+++ b/fuse/peripherals/disk/upd_fdc.h
@@ -139,6 +139,7 @@ typedef struct upd_fdc {
int cycle; /* read/write cycle num */
int del_data; /* READ/WRITE deleted data */
int mt; /* multitrack operations */
+ int tc; /* Terminal Count asserted */
int mf; /* MFM mode */
int sk; /* skip deleted/not deleted data */
int hd; /* physical head address */
@@ -173,6 +174,7 @@ void upd_fdc_init_events( void );
/* allocate an fdc */
upd_fdc *upd_fdc_alloc_fdc( upd_type_t type, upd_clock_t clock );
void upd_fdc_master_reset( upd_fdc *f );
+void upd_fdc_tc( upd_fdc *f, int tc );
libspectrum_byte upd_fdc_read_status( upd_fdc *f );
commit 19f9c35c74649388ec5254dd501e6f0d90c97eb9
Author: Alex Badea <abadea@ixiacom.com>
Date: Fri Jun 22 12:53:49 2012 +0300
debugger: add support for setting IM and IFFs
---
fuse/debugger/command.c | 18 ++++++++++++++++++
fuse/debugger/commandl.l | 3 +++
2 files changed, 21 insertions(+)
diff --git a/fuse/debugger/command.c b/fuse/debugger/command.c
index 2be43b0..28d8429 100644
--- a/fuse/debugger/command.c
+++ b/fuse/debugger/command.c
@@ -130,6 +130,9 @@ debugger_register_hash( const char *name )
case 0x7063: /* PC */
case 0x6978: /* IX */
case 0x6979: /* IY */
+ case 0x696d: /* IM */
+ case 0x69666631: /* IFF1 */
+ case 0x69666632: /* IFF2 */
return hash;
default: return -1;
@@ -184,6 +187,11 @@ debugger_register_get( int which )
case 0x6978: return IX;
case 0x6979: return IY;
+ /* interrupt flags */
+ case 0x696d: return IM;
+ case 0x69666631: return IFF1;
+ case 0x69666632: return IFF2;
+
default:
ui_error( UI_ERROR_ERROR, "attempt to get unknown register '%d'", which );
return 0;
@@ -229,6 +237,11 @@ debugger_register_set( int which, libspectrum_word value )
case 0x6978: IX = value; break;
case 0x6979: IY = value; break;
+ /* interrupt flags */
+ case 0x696d: IM = value; break;
+ case 0x69666631: IFF1 = value; break;
+ case 0x69666632: IFF2 = value; break;
+
default:
ui_error( UI_ERROR_ERROR, "attempt to set unknown register '%d'", which );
break;
@@ -274,6 +287,11 @@ debugger_register_text( int which )
case 0x6978: return "IX";
case 0x6979: return "IY";
+ /* interrupt flags */
+ case 0x696d: return "IM";
+ case 0x69666631: return "IFF1";
+ case 0x69666632: return "IFF2";
+
default:
ui_error( UI_ERROR_ERROR, "attempt to get unknown register '%d'", which );
return "(invalid)";
diff --git a/fuse/debugger/commandl.l b/fuse/debugger/commandl.l
index 0439df9..a07268e 100644
--- a/fuse/debugger/commandl.l
+++ b/fuse/debugger/commandl.l
@@ -96,6 +96,9 @@ af|bc|de|hl|"af\'"|"bc\'"|"de\'"|"hl\'" {
sp|pc|ix|iy { yylval.reg = debugger_register_hash( yytext );
return DEBUGGER_REGISTER; }
+im|iff1|iff2 { yylval.reg = debugger_register_hash( yytext );
+ return DEBUGGER_REGISTER; }
+
"(" { return '('; }
")" { return ')'; }
commit 1debab6dcfe96ca20d2a5251bcca4854125a8c88
Author: Alex Badea <abadea@ixiacom.com>
Date: Fri Jun 22 12:54:52 2012 +0300
gtk debugger: use MEMORY_PAGE_SIZE instead of hard-coded 4k
This fixes values displayed in the Memory Map.
---
fuse/ui/gtk/debugger.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fuse/ui/gtk/debugger.c b/fuse/ui/gtk/debugger.c
index cbc2d30..86815a9 100644
--- a/fuse/ui/gtk/debugger.c
+++ b/fuse/ui/gtk/debugger.c
@@ -823,7 +823,7 @@ update_memory_map( void )
char buffer[40];
GtkWidget **row_labels = map_label[row];
- snprintf( buffer, 40, format_16_bit(), (unsigned)block * 0x1000 );
+ snprintf( buffer, 40, format_16_bit(), (unsigned)block * MEMORY_PAGE_SIZE );
row_labels[0] = gtk_label_new( buffer );
snprintf( buffer, 40, "%s %d",
commit 539e3476ff3ae32608fd13d3ed902bae99660c3d
Author: Alex Badea <abadea@ixiacom.com>
Date: Fri Jun 22 12:55:49 2012 +0300
disk: allow reading mgt layouts of 80x16x256 and 40x16x256
---
fuse/peripherals/disk/disk.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/fuse/peripherals/disk/disk.c b/fuse/peripherals/disk/disk.c
index f8aa264..451bc6e 100644
--- a/fuse/peripherals/disk/disk.c
+++ b/fuse/peripherals/disk/disk.c
@@ -1100,7 +1100,11 @@ open_img_mgt_opd( buffer_t *buffer, disk_t *d )
* 2*80*10*512, 1*80*10*512, 1*40*10*512, 1*40*18*256, 1*80*18*256,
* 2*80*18*256
*/
- if( buffer->file.length == 2*80*10*512 ) {
+ if( buffer->file.length == 2*80*16*256 ) {
+ d->sides = 2; d->cylinders = 80; sectors = 16; seclen = 256;
+ } else if( buffer->file.length == 2*40*16*256 ) {
+ d->sides = 2; d->cylinders = 40; sectors = 16; seclen = 256;
+ } else if( buffer->file.length == 2*80*10*512 ) {
d->sides = 2; d->cylinders = 80; sectors = 10; seclen = 512;
} else if( buffer->file.length == 1*80*10*512 ) {
/* we cannot distinguish between a single sided 80 track image
commit f90555b0aad4ccbf248bd1f3708d5d4648314457
Author: Alex Badea <abadea@ixiacom.com>
Date: Fri Jun 22 12:56:48 2012 +0300
HACK disk: disable size checking when writing .mgt images
We use 80x16x256 and 40x16x256. We should add these to the supported
layouts instead of entirely disabling checking.
---
fuse/peripherals/disk/disk.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/fuse/peripherals/disk/disk.c b/fuse/peripherals/disk/disk.c
index 451bc6e..67b71a5 100644
--- a/fuse/peripherals/disk/disk.c
+++ b/fuse/peripherals/disk/disk.c
@@ -2128,10 +2128,15 @@ write_img_mgt_opd( FILE *file, disk_t *d )
{
int i, j, sbase, sectors, seclen, mfm, cyl;
+ check_disk_geom( d, &sbase, §ors, &seclen, &mfm, &cyl );
+ fprintf(stderr, "%s: sbase=%d sectors=%d seclen=%d cyl=%d\n", __func__, sbase, sectors, seclen, cyl);
+
+/*
if( check_disk_geom( d, &sbase, §ors, &seclen, &mfm, &cyl ) ||
( d->type != DISK_OPD && ( sbase != 1 || seclen != 2 || sectors != 10 ) ) ||
( d->type == DISK_OPD && ( sbase != 0 || seclen != 1 || sectors != 18 ) ) )
return d->status = DISK_GEOM;
+*/
if( cyl == -1 ) cyl = d->cylinders;
if( cyl != 40 && cyl != 80 )
commit 064504f340231034327dcf6be137b23205fcced7
Author: Alex Badea <abadea@ixiacom.com>
Date: Fri Jun 22 12:59:24 2012 +0300
HACK disk: add a bunch of fprintf() debug logging
---
fuse/peripherals/disk/fdd.c | 1 +
fuse/peripherals/disk/upd_fdc.c | 40 +++++++++++++++++++++++++++++++++++++--
2 files changed, 39 insertions(+), 2 deletions(-)
diff --git a/fuse/peripherals/disk/fdd.c b/fuse/peripherals/disk/fdd.c
index 878019d..7ee37fb 100644
--- a/fuse/peripherals/disk/fdd.c
+++ b/fuse/peripherals/disk/fdd.c
@@ -209,6 +209,7 @@ fdd_head_load( fdd_t *d, int load )
void
fdd_select( fdd_t *d, int select )
{
+fprintf(stderr, "%s: fdd=%p select=%d\n", __func__, d, select); // XXX
d->selected = select > 0 ? 1 : 0;
/*
... Drive Select when activated to a logical
diff --git a/fuse/peripherals/disk/upd_fdc.c b/fuse/peripherals/disk/upd_fdc.c
index ca6db57..0839a33 100644
--- a/fuse/peripherals/disk/upd_fdc.c
+++ b/fuse/peripherals/disk/upd_fdc.c
@@ -264,6 +264,7 @@ read_datamark( upd_fdc *f )
if( d->fdd.data == 0x00 ) /* go to PLL sync */
break;
+fprintf(stderr, "%s:%d: data 0x%02x\n", __func__, __LINE__, d->fdd.data);
f->status_register[2] |= UPD_FDC_ST2_MISSING_DM;
return 1; /* something wrong... */
}
@@ -276,18 +277,21 @@ read_datamark( upd_fdc *f )
if( d->fdd.data == 0xffa1 ) /* got to a1 mark */
break;
+fprintf(stderr, "%s:%d: data 0x%02x\n", __func__, __LINE__, d->fdd.data);
f->status_register[2] |= UPD_FDC_ST2_MISSING_DM;
return 1;
}
for( i = d->fdd.data == 0xffa1 ? 2 : 3; i > 0; i-- ) {
fdd_read_write_data( &d->fdd, FDD_READ ); crc_add( f, d );
if( d->fdd.data != 0xffa1 ) {
+fprintf(stderr, "%s:%d: data 0x%02x\n", __func__, __LINE__, d->fdd.data);
f->status_register[2] |= UPD_FDC_ST2_MISSING_DM;
return 1;
}
}
fdd_read_write_data( &d->fdd, FDD_READ ); crc_add( f, d );
if( d->fdd.data < 0x00f8 || d->fdd.data > 0x00fb ) { /* !fb deleted mark */
+fprintf(stderr, "%s:%d: data 0x%02x\n", __func__, __LINE__, d->fdd.data);
f->status_register[2] |= UPD_FDC_ST2_MISSING_DM;
return 1;
}
@@ -305,6 +309,7 @@ read_datamark( upd_fdc *f )
if( d->fdd.data == 0x00 ) /* go to PLL sync */
break;
+fprintf(stderr, "%s:%d: data 0x%02x\n", __func__, __LINE__, d->fdd.data);
f->status_register[2] |= UPD_FDC_ST2_MISSING_DM;
return 1; /* something wrong... */
}
@@ -317,12 +322,14 @@ read_datamark( upd_fdc *f )
if( d->fdd.data >= 0xfff8 && d->fdd.data <= 0xfffb ) /* !fb deleted mark */
break;
+fprintf(stderr, "%s:%d: data 0x%02x\n", __func__, __LINE__, d->fdd.data);
f->status_register[2] |= UPD_FDC_ST2_MISSING_DM;
return 1;
}
if( i == 0 ) {
fdd_read_write_data( &d->fdd, FDD_READ ); crc_add( f, d );
if( d->fdd.data < 0xfff8 || d->fdd.data > 0xfffb ) { /* !fb deleted mark */
+fprintf(stderr, "%s:%d: data 0x%02x\n", __func__, __LINE__, d->fdd.data);
f->status_register[2] |= UPD_FDC_ST2_MISSING_DM;
return 1;
}
@@ -333,6 +340,7 @@ read_datamark( upd_fdc *f )
f->ddam = 0;
return 0;
}
+fprintf(stderr, "%s:%d: data 0x%02x\n", __func__, __LINE__, d->fdd.data);
f->status_register[2] |= UPD_FDC_ST2_MISSING_DM;
return 1;
}
@@ -399,6 +407,17 @@ upd_fdc_alloc_fdc( upd_type_t type, upd_clock_t clock )
static void
cmd_result( upd_fdc *f )
{
+fprintf(stderr, "%s: cmd 0x%x, status: %02x %02x %02x, data %02x %02x %02x %02x %02x\n",
+ __func__, f->cmd->value,
+ f->status_register[0],
+ f->status_register[1],
+ f->status_register[2],
+ f->data_register[0],
+ f->data_register[1],
+ f->data_register[2],
+ f->data_register[3],
+ f->data_register[4]);
+
f->cycle = f->cmd->res_length;
f->main_status &= ~UPD_FDC_MAIN_EXECUTION;
f->main_status |= UPD_FDC_MAIN_DATAREQ;
@@ -572,6 +591,7 @@ start_read_data( upd_fdc *f )
int i;
skip_deleted_sector:
multi_track_next:
+fprintf(stderr, "%s: start (tc=%d)\n", __func__, f->tc);
if( f->first_rw || f->read_id ||
(!f->tc && f->data_register[5] > f->data_register[3]) ) {
if( !f->read_id ) {
@@ -617,6 +637,7 @@ multi_track_next:
}
}
} else {
+fprintf(stderr, "%s: check (mt=%d tc=%d)\n", __func__, f->mt, f->tc);
if( f->mt ) {
f->data_register[1]++; /* next track */
f->data_register[3] = 1; /* first sector */
@@ -630,7 +651,7 @@ abort_read_data:
* (i.e. no other errors occur like no data.
* 2. sector being read is same specified by EOT
* 3. terminal count is not received
-* note: in +3 uPD765 never got TC
+* note: in +3 uPD765 never got TC (FIXME)
*/
if( !f->status_register[0] && !f->status_register[1] && !f->tc ) {
f->status_register[0] |= UPD_FDC_ST0_INT_ABNORM;
@@ -648,6 +669,7 @@ abort_read_data:
cmd_result( f );
return;
}
+
f->main_status |= UPD_FDC_MAIN_DATAREQ;
if( f->cmd->id != UPD_CMD_SCAN )
f->main_status |= UPD_FDC_MAIN_DATA_READ;
@@ -731,7 +753,7 @@ abort_write_data:
* (i.e. no other errors occur like no data.
* 2. sector being read is same specified by EOT
* 3. terminal count is not received
-* note: in +3 uPD765 never got TC
+* note: in +3 uPD765 never got TC (FIXME)
*/
if( !f->tc ) {
f->status_register[0] |= UPD_FDC_ST0_INT_ABNORM;
@@ -890,6 +912,7 @@ upd_fdc_read_data( upd_fdc *f )
return 0xff;
if( f->state == UPD_FDC_STATE_EXE ) { /* READ_DATA/READ_DIAG */
+
f->data_offset++; /* count read bytes */
fdd_read_write_data( &d->fdd, FDD_READ ); crc_add( f, d ); /* read a byte */
@@ -1157,6 +1180,15 @@ upd_fdc_write_data( upd_fdc *f, libspectrum_byte data )
f->data_register[f->cycle - 1] = data; /* store data register bytes */
}
if( f->cycle >= f->cmd->cmd_length ) { /* we already read all neccessery byte */
+fprintf(stderr, "%s: cmd 0x%02x data %02x %02x %02x %02x %02x %02x %02x %02x\n", __func__, f->cmd->value,
+ f->data_register[0],
+ f->data_register[1],
+ f->data_register[2],
+ f->data_register[3],
+ f->data_register[4],
+ f->data_register[5],
+ f->data_register[6],
+ f->data_register[7]);
f->state = UPD_FDC_STATE_EXE; /* start execution of the command */
f->main_status &= ~UPD_FDC_MAIN_DATAREQ;
if( f->non_dma ) { /* btw: only NON-DMA mode emulated */
@@ -1358,8 +1390,12 @@ upd_fdc_write_data( upd_fdc *f, libspectrum_byte data )
}
}
+/* Signal the state of the Terminal Count input. */
void upd_fdc_tc( upd_fdc *f, int tc )
{
+fprintf(stderr, "%s: tc=%d data_offset=%d rlen=%d status: %02x %02x\n", __func__,
+ tc, f->data_offset, f->rlen, f->status_register[0], f->status_register[1]);
+
if (tc > 0)
f->tc = 1;
}
commit 09637da45885114a5d250b361c4eb60470850003
Author: Alex Badea <abadea@ixiacom.com>
Date: Fri Jun 22 13:00:15 2012 +0300
memory: change page size from 4k to 1k
The HC Interface1 hardware has a 1K RAM region which is selected into
multiple pages.
---
fuse/memory.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fuse/memory.h b/fuse/memory.h
index 6b9c72c..23a1321 100644
--- a/fuse/memory.h
+++ b/fuse/memory.h
@@ -64,7 +64,7 @@ typedef struct memory_page {
/* A memory page will be 1 << (this many) bytes in size
ie 12 => 4 Kb, 13 => 8 Kb, 14 => 16 Kb
*/
-#define MEMORY_PAGE_SIZE_LOGARITHM 12
+#define MEMORY_PAGE_SIZE_LOGARITHM 10
/* The actual size of a memory page */
#define MEMORY_PAGE_SIZE ( 1 << MEMORY_PAGE_SIZE_LOGARITHM )
commit 856cbbc92d7c1c8f9b4e752b99c8c65321fadee3
Author: Alex Badea <abadea@ixiacom.com>
Date: Fri Jun 22 13:00:30 2012 +0300
HACK if1: add HC uPD disk interface support
---
fuse/peripherals/if1.c | 250 ++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 244 insertions(+), 6 deletions(-)
diff --git a/fuse/peripherals/if1.c b/fuse/peripherals/if1.c
index 8fcc82e..4e53a4f 100644
--- a/fuse/peripherals/if1.c
+++ b/fuse/peripherals/if1.c
@@ -40,17 +40,22 @@
#include "memory.h"
#include "module.h"
#include "periph.h"
+#include "peripherals/disk/fdd.h"
+#include "peripherals/disk/upd_fdc.h"
#include "settings.h"
#include "utils.h"
#include "ui/ui.h"
#include "unittests/unittests.h"
#undef IF1_DEBUG_MDR
-#undef IF1_DEBUG_NET
+#define IF1_DEBUG_NET
#undef IF1_DEBUG_NET_1
#define BUFF_EMPTY 0x100
+//#define debug_fdc(fmt, args...) fprintf(stderr, "%s:%d: " fmt "\n", __func__, __LINE__, ## args)
+#define debug_fdc(x...)
+
enum {
SYNC_NO = 0,
SYNC_OK = 0xff
@@ -155,8 +160,41 @@ RS232:
every other 0x00 + 0x## are discarded
*/
+/*
+ HC IF1
+
+ 7 6 5 4 3 2 1 0
+ STATUS RO $EF(239) --- --- --- --- DTR --- --- ---
+
+ CONTRO WO $EF(239) --- --- WAT CTS --- --- --- DTA
+
+ COMM I RO $F7(247) TXD --- --- --- --- --- --- NIN
+
+ COMM O WO $F7(247) --- --- --- --- --- --- --- nNET/RS232
+
+
+ BOTH I RO $E7 TXD --- --- --- DTR --- --- NIN
+
+
+ FDSEL I ($05/$07) --- --- --- --- --- --- --- MOTOR_ON
+ FDSEL O ($05/$07) --- --- --- RST 555 FD1 FD2 ---
+
+ $85 I i8272 status
+ $87 I i8272 data
+ $87 O i8272 command
+
+?
+ Address lines: A7 A6 A5 A4 A3 A2 A1 A0
+ $FE (spectrum port) 1 0
+ $7E (sys config) 0 0
+ $F7 (NET) 0 [not 000] 0
+ $F7 (NET) 1 [not 000] 0 1
+ $EF (CTR) [! 00] 0 1
+
+ */
+
/* One 8KB memory chunk accessible by the Z80 when /ROMCS is low */
-static memory_page if1_memory_map_romcs[MEMORY_PAGES_IN_8K];
+static memory_page if1_memory_map_romcs[MEMORY_PAGES_IN_16K];
/* IF1 paged out ROM activated? */
int if1_active = 0;
@@ -193,6 +231,7 @@ enum if1_port {
PORT_MDR,
PORT_CTR,
PORT_NET,
+ PORT_BOTH,
PORT_UNKNOWN,
};
@@ -201,6 +240,20 @@ static void if1_enabled_snapshot( libspectrum_snap *snap );
static void if1_from_snapshot( libspectrum_snap *snap );
static void if1_to_snapshot( libspectrum_snap *snap );
+
+#define IF1_NUM_DRIVES 2
+upd_fdc *if1_fdc;
+static upd_fdc_drive if1_drives[ IF1_NUM_DRIVES ];
+
+void if1_fdc_reset( void );
+void if1_fdc_init( void );
+
+libspectrum_byte if1_fdc_status( libspectrum_word port, int *attached );
+libspectrum_byte if1_fdc_read( libspectrum_word port, int *attached );
+void if1_fdc_write( libspectrum_word port, libspectrum_byte data );
+libspectrum_byte if1_fdc_sel_read( libspectrum_word port, int *attached );
+void if1_fdc_sel_write( libspectrum_word port, libspectrum_byte data );
+
static module_info_t if1_module_info = {
if1_reset,
@@ -212,9 +265,15 @@ static module_info_t if1_module_info = {
};
static const periph_port_t if1_ports[] = {
+ { 0x00fd, 0x0005, if1_fdc_sel_read, if1_fdc_sel_write },
+ { 0x00ff, 0x0085, if1_fdc_status, NULL },
+ { 0x00ff, 0x0087, if1_fdc_read, if1_fdc_write },
{ 0x0018, 0x0010, if1_port_in, if1_port_out },
{ 0x0018, 0x0008, if1_port_in, if1_port_out },
{ 0x0018, 0x0000, if1_port_in, if1_port_out },
+/*
+ { 0x0001, 0x0001, if1_port_in, if1_port_out },
+*/
{ 0, 0, NULL, NULL }
};
@@ -333,8 +392,14 @@ if1_init( void )
settings_current.snet = NULL;
}
+ if1_fdc_init();
+
module_register( &if1_module_info );
+ if1_memory_source = memory_source_register( "If1r" );
+ for( i = MEMORY_PAGES_IN_8K; i < MEMORY_PAGES_IN_16K; i++ )
+ if1_memory_map_romcs[i].source = if1_memory_source;
+
if1_memory_source = memory_source_register( "If1" );
for( i = 0; i < MEMORY_PAGES_IN_8K; i++ )
if1_memory_map_romcs[i].source = if1_memory_source;
@@ -364,6 +429,9 @@ if1_update_menu( void )
update_menu( UMENU_ALL );
}
+/* The number of memory pages in 1K */
+#define MEMORY_PAGES_IN_1K ( 1 << ( 10 - MEMORY_PAGE_SIZE_LOGARITHM ) )
+
static void
if1_reset( int hard_reset GCC_UNUSED )
{
@@ -381,6 +449,20 @@ if1_reset( int hard_reset GCC_UNUSED )
return;
}
+ if (1) { /* XXX */
+ int j;
+
+ libspectrum_byte *ram =
+ memory_pool_allocate_persistent( 1024 /* IF1_HC_RAM_LENGTH */, 1 );
+
+ for( j = 0; j < MEMORY_PAGES_IN_8K; j++ ) {
+ memory_page *page = &if1_memory_map_romcs[MEMORY_PAGES_IN_8K + j];
+ /* HACK: assumes page size is 1K */
+ page->writable = (j % 4) >= 2;
+ page->page = ram;
+ }
+ }
+
machine_current->ram.romcs = 0;
if1_ula.cts = 2; /* force to emit first out if raw */
@@ -390,6 +472,7 @@ if1_reset( int hard_reset GCC_UNUSED )
if1_ula.esc_in = 0;
microdrives_reset();
+ if1_fdc_reset();
update_menu( UMENU_ALL );
ui_statusbar_update( UI_STATUSBAR_ITEM_MICRODRIVE,
@@ -426,7 +509,8 @@ if1_memory_map( void )
if( !if1_active ) return;
memory_map_romcs_8k( 0x0000, if1_memory_map_romcs );
- memory_map_romcs_8k( 0x2000, if1_memory_map_romcs );
+ //memory_map_romcs_8k( 0x2000, if1_memory_map_romcs );
+ memory_map_romcs_8k( 0x2000, if1_memory_map_romcs + MEMORY_PAGES_IN_8K );
}
static void
@@ -527,7 +611,8 @@ static enum if1_port
decode_port( libspectrum_word port )
{
switch( port & 0x0018 ) {
- case 0x0000: return PORT_MDR;
+ //case 0x0000: return PORT_MDR;
+ case 0x0000: return PORT_BOTH;
case 0x0008: return PORT_CTR;
case 0x0010: return PORT_NET;
default: return PORT_UNKNOWN;
@@ -767,6 +852,9 @@ if1_port_in( libspectrum_word port GCC_UNUSED, int *attached )
{
libspectrum_byte ret = 0xff;
+ if (!(port & 0x70))
+ return 0xff;
+
*attached = 1;
switch( decode_port( port ) )
@@ -774,9 +862,14 @@ if1_port_in( libspectrum_word port GCC_UNUSED, int *attached )
case PORT_MDR: ret &= port_mdr_in(); break;
case PORT_CTR: ret &= port_ctr_in(); break;
case PORT_NET: ret &= port_net_in(); break;
+ case PORT_BOTH:
+ ret = (port_net_in() & 0x81) | (port_ctr_in() & 0x08);
+ break;
case PORT_UNKNOWN: break;
}
+ debug_fdc("port 0x%02x (%d) --> 0x%02x", port & 0xff, decode_port(port), ret);
+
return ret;
}
@@ -1006,11 +1099,20 @@ if1_port_out( libspectrum_word port GCC_UNUSED, libspectrum_byte val )
!!(val & 8), !!(val & 4), !!(val & 2), !!(val & 1), port);
#endif
+ if (!(port & 0x70))
+ return;
+
+ debug_fdc("port 0x%02x <- 0x%02x", port & 0xff, val);
+
switch( decode_port( port ) ) {
case PORT_MDR: port_mdr_out( val ); break;
- case PORT_CTR: port_ctr_out( val ); break;
- case PORT_NET: port_net_out( val ); break;
+ case PORT_CTR: port_ctr_out( val & 0x31 ); break;
+ case PORT_NET: port_net_out( val & 0x01 ); break;
case PORT_UNKNOWN: break;
+ case PORT_BOTH:
+ port_ctr_out(val & 0x31);
+ port_net_out(val & 0x01);
+ break;
}
}
@@ -1339,3 +1441,139 @@ if1_unittest( void )
return r;
}
+
+libspectrum_byte
+if1_fdc_status( libspectrum_word port GCC_UNUSED, int *attached )
+{
+ libspectrum_byte ret;
+ *attached = 1;
+ ret = upd_fdc_read_status( if1_fdc );
+// debug_fdc("port 0x%02x --> 0x%02x", port & 0xff, ret);
+ return ret;
+}
+
+libspectrum_byte
+if1_fdc_read( libspectrum_word port GCC_UNUSED, int *attached )
+{
+ libspectrum_byte ret;
+ *attached = 1;
+ ret = upd_fdc_read_data( if1_fdc );
+ debug_fdc("port 0x%02x --> 0x%02x", port & 0xff, ret);
+ return ret;
+}
+
+void
+if1_fdc_write( libspectrum_word port GCC_UNUSED, libspectrum_byte data )
+{
+ debug_fdc("port 0x%02x <-- 0x%02x", port & 0xff, data);
+ upd_fdc_write_data( if1_fdc, data );
+}
+
+libspectrum_byte
+if1_fdc_sel_read( libspectrum_word port GCC_UNUSED, int *attached )
+{
+ libspectrum_byte ret;
+ *attached = 1;
+ ret = 0xff;
+ debug_fdc("port 0x%02x --> 0x%02x", port & 0xff, ret);
+ return ret;
+}
+
+void
+if1_fdc_sel_write( libspectrum_word port GCC_UNUSED, libspectrum_byte data )
+{
+ libspectrum_byte armed;
+
+ debug_fdc("port 0x%02x <-- 0x%02x", port & 0xff, data);
+
+ if (!(data & 0x10)) {
+ debug_fdc("if1: FDC reset");
+ upd_fdc_master_reset(if1_fdc);
+ }
+ upd_fdc_tc(if1_fdc, data & 1);
+
+ armed = data & 0x08;
+ if (!armed) {
+// if1_drives[0].disk.type = DISK_TYPE_NONE;
+// fprintf(stderr, "### disk_write log: %d\n", disk_write(&if1_drives[0].disk, "/tmp/hc-if1-disk.log")); // HACK
+ if1_drives[0].disk.type = DISK_TYPE_NONE;
+// debug_fdc( "### disk_write udi: %d", disk_write(&if1_drives[0].disk, "/tmp/hc-if1-disk.udi")); // HACK
+ fprintf(stderr, "### disk_write mgt: %d\n", disk_write(&if1_drives[0].disk, "/tmp/hc-if1-disk.mgt")); // HACK
+// fprintf(stderr, "### disk_write img: %d\n", disk_write(&if1_drives[0].disk, "/tmp/hc-if1-disk.img")); // HACK
+// if1_drives[0].disk.type = DISK_LOG;
+ }
+
+
+ /* TODO: monostable delay */
+ //armed = data & 0x08;
+ armed = 1;
+ fdd_select(&if1_drives[0].fdd, armed && (data & 0x02));
+ fdd_select(&if1_drives[1].fdd, armed && (data & 0x04));
+ fdd_motoron(&if1_drives[0].fdd, armed && (data & 0x02));
+ fdd_motoron(&if1_drives[1].fdd, armed && (data & 0x04));
+}
+
+void
+if1_fdc_init( void )
+{
+ upd_fdc_drive *d;
+ int err;
+
+ if1_fdc = upd_fdc_alloc_fdc( UPD765A, UPD_CLOCK_8MHZ );
+ if1_fdc->drive[0] = &if1_drives[ 0 ];
+ if1_fdc->drive[1] = &if1_drives[ 1 ];
+ if1_fdc->drive[2] = &if1_drives[ 0 ];
+ if1_fdc->drive[3] = &if1_drives[ 1 ];
+
+ fdd_init( &if1_drives[ 0 ].fdd, FDD_SHUGART, &fdd_params[ 4 ], 0 );
+ fdd_init( &if1_drives[ 1 ].fdd, FDD_SHUGART, &fdd_params[ 1 ], 0 ); /* drive geometry 'autodetect' */
+ if1_fdc->set_intrq = NULL;
+ if1_fdc->reset_intrq = NULL;
+ if1_fdc->set_datarq = NULL;
+ if1_fdc->reset_datarq = NULL;
+
+ d = &if1_drives[0];
+ err = disk_open( &d->disk, "/tmp/hc-if1-disk.mgt", 0, 0);
+ fprintf(stderr, "disk_open: %d\n", err);
+ if (err) {
+ err = disk_new(&d->disk,
+ 2 /* heads */,
+ 80 /* cylinders */,
+ DISK_DENS_AUTO /* DISK_DENS_AUTO */,
+ DISK_LOG /* DISK_UDI? _NONE? */);
+ fprintf(stderr, "disk_new: %d\n", err);
+ }
+
+ err = fdd_load( &d->fdd, &d->disk, 0 );
+ debug_fdc("fdc_load(%p): %d", &d->fdd, err);
+
+
+ d = &if1_drives[1];
+ if (1) {
+ err = disk_new(&d->disk,
+ 2 /* heads */,
+ 40 /* cylinders */,
+ DISK_DENS_AUTO /* DISK_DENS_AUTO */,
+ DISK_LOG /* DISK_UDI? _NONE? */);
+ fprintf(stderr, "disk_new: %d\n", err);
+ }
+ err = fdd_load( &d->fdd, &d->disk, 0 );
+ debug_fdc("fdc_load(%p): %d", &d->fdd, err);
+}
+
+void
+if1_fdc_reset( void )
+{
+ const fdd_params_t *dt;
+
+ upd_fdc_master_reset( if1_fdc );
+ dt = &fdd_params[4];
+ fdd_init( &if1_drives[ 0 ].fdd, FDD_SHUGART, dt, 1 );
+
+ dt = &fdd_params[2];
+ fdd_init( &if1_drives[ 1 ].fdd, dt->enabled ? FDD_SHUGART : FDD_TYPE_NONE, dt, 1 );
+}
+
+/*
+vampire@black:~/src/fuse-emulator/fuse$ ~/build/fuse-git/fuse/fuse -m 48 --rom-48=roms/HC/HC-90/BAS --rom-interface-i=roms/HC/HC-90/IF1.trunc --interface1 > /tmp/fuse.log 2>&1
+ */