Changes

Jump to: navigation, search

FPGAmstrad

1,728 bytes removed, 17:13, 23 August 2017
/* Z80 architecture : T80_ALU.vhdl */
[[File:ghostngoblins.jpg]]
== How to assemble it ==NEXYS2 Xilinx version is obsolete, it is still describe here for history reason (showing the prototyping part). Please refer to [[http://github.com/mist-devel/mist-board/wiki/CoreDocAmstrad MiST-board CoreDocAmstrad]] for the final user version, running on MiST-board platform.
'''You need:'''
----
 
==Video==
http://www.youtube.com/watch?v=Z8FB_eIy8LY
== Last news about this project ==
In May 2017, FPGAmstrad TV mode is validated using a TV from Tetalab group. In February 2017, CRTC1 is also implemented following JavaCPC's source code, now you can choose between CRTC0 and CRTC1 in the OSD menu. In January 2017, scanlines mode is implemented, you can select it from the OSD menu. In December 2017, implementing green screen, using "Les Sucres en Morceaux" tutorial. In September 2016, FPGAmstrad does use external RAM as RAM+VRAM, no more "LowerVRAM/UpperVRAM" switches to select in the OSD menu.
[[File:Fpgamstrad jocker batdemo.png|thumbnail|Using 64K of VRAM...]]
*'''split ink demo.dsk''': (from cpcrulez) : may help about ink raster calibration.
*'''Sultan's Maze.dsk''': does need the right part of keyboard (F0-F9 are used for directions in this game)
*'''Orion Primes.dsk''': does display "secteurs entrelacés" - "vérifiez votre copie", a FDC problem, perhaps "sectorId++" is not the good way to reach next sector, or else two tracks in one track.
*'''Batman_Forever.dsk''': some problem during flying chip demo part, and several rupture showing ghost lines around Vcc=0.
*'''30YMD.dsk''': in Benediction demo, at bottom some time you see some ghosts of central animation (too many HSync per screen ?)
'''Nigel Mansell's Grand Prix.dsk''': Only one race track seems ok : Monaco (Brazil track does not start). Unclassified : this disk bug also with other emulators, certainly a bad dsk dump here, TOSEC version of Nigel Mansell does run fine (but some legendary traces of "SK bit purpose" needed by here (in FDC, setting SK does jump deleted disk tracks), perhaps to investigate)- update : some tracks unlocked in r005.8.15c61.
'''saboteur2.dsk''': run fine since r005.5 (nice music and then freeze problem), it was about Yamaha clock generator (generated by Gatearray, versus WAIT_n added in short Z80 instruction to let them during all 4 clocks (Z80 in Amstrad does use 4T or 8T instructions (WAIT_n does insert missing T)). Does freeze at welcome since r005.8.7. Back since r005.8.10.
[http://www.winape.net/download/plustest.zip WinAPE plustest.zip (including Instruction and Interrupt timing tests)]
 
===== Z80 architecture : T80.vhdl =====
17 pages of source codes to read.
 
Not analyzed yet completly.
 
Contains the main workflow of Z80: current MCycle and its current TState.
 
Contains T80_ALU.vhdl and T80_MCode.vhdl components.
 
===== Z80 architecture : T80_ALU.vhdl =====
6 pages of source codes to read.
 
Not analyzed yet completly. This analyse can certainly be wrong : wip.
 
Contains flags : C N P X H Y Z S
C : carry - set if result did not fit in the register
N : negative? - last instruction was substract
P : parity or overflow - overflow example : signed, 7F+7F=FE with overflow setted
X : undocumented
H : half carry - set if 4bit first bits of result did not fit in the register
Y : undocumented
Z : zero - set if result is zero
S : sign - it is an input ?
Contains ALU_Op : [ADD ADC SUB SBC AND XOR OR CP] ROT BIT [SET RES] DAA
 
ALU_Op is the basic instructions of Z80 coded here. T80_ALU.vhdl is a slave, a service exposed to T80_MCode.vhdl throw T80.vhdl
 
[[http://www.z80.info/decoding.htm § Disassembly tables]] shall make a cool ALU_Op quick reference card, doesn't it ?
 
===== Z80 architecture : T80_MCode.vhdl =====
First 5 pages, and last 2 pages of source codes to read. Others pages are "always the same" architectually speaking.
 
Not analyzed yet completly. This analyse can certainly be wrong : wip.
 
Gives instructions lengh : MCycles, TStates (please remark the 's' at end of theses words...), in [[http://www.zilog.com/docs/z80/um0080.pdf Z80 doc]] each instruction is timing described using "M Cycles" and "T States" vocabulary.
 
It's a "controler" (proof : you have some Set_*_To outputs), does gives orders to T80_ALU.vhdl throw T80.vhdl
 
Actions of this controler are :
* ALU_Op : the action !
* I_DJNZ I_CPL I_CCF I_SCF I_RETN I_BT I_BC I_BTR I_RLD I_RRD I_INRC : actions not for ALU (wiring input/ouput, changing flags...)
* Save_ALU/PreserveC : an option about register "erased or not" at next instruction
Instructions not coded in T80_MCode.vhdl but in T80.vhdl (strange, barbarian part of code ?) :
* Jump/E/XY Call RstP LDZ LDW LDSPHL Special_LD ExchangeDH/Dp/AF/RS
 
Inc_WZ register : take a look at [[http://www.righto.com/2014/10/how-z80s-registers-are-implemented-down.html § The WZ temporary registers]. It's a tmp internal register in fact.
=== Alignment of HSYNC Interrupt ===
[[File:Cpmpluf1.dsk.png|thumbnail|CP/M+ fr disk inserted (cpmpluf1.dsk)]]
"Wrong disk for your configuration" message seen in one-disk version of "Batman Forever" demo (two separate disk version runs fine), in forum they say that dsk image is using "bad track numbers", in fact when looking at a Track-Info with side 1 (instead of 0), track and side are correct in Track-Info but side is not ok in Sector-Info, normaly track/side are ignored in Sector-Info (Track-Info is used for that)... but still having the message, something else seems also wrong.
Do fix also message "Bad Command" while running a not existing file on disk.
Certainly linked to ''Orion Primes.dsk'' loading problem.
 
==== FDC Basic testbench ====
Results from WinAPE... (left Alt is "COPY" key)
 
SEEK.BAS :
5 OUT &FA7E,1:PRINT"MOTOR ON":PRINT"GOSUB 520 : MOTOR OFF"
10 PRINT "GOSUB 40 : RECALIBRATE":PRINT "GOSUB 70 : SEEK"
20 PRINT "GOSUB 110 : SENSE_INTERRUPT_STATUS":PRINT "GOSUB 150 : STATUS"
25 PRINT "GOSUB 170 : READ_DATA":PRINT "GOSUB 420 : READ_ID"
30 END
40 OUT &FB7F,&X00000111
50 OUT &FB7F,&X00000000:PRINT"US1 US0)
60 RETURN
70 OUT &FB7F,&X00001111
80 OUT &FB7F,&X00000000:PRINT"HD US1 US0)"
90 OUT &FB7F,&X00000010:PRINT"TRACK"
100 RETURN
110 OUT &FB7F,&X00001000
120 PRINT BIN$(INP(&FB7F),8):PRINT"ST0"
130 PRINT BIN$(INP(&FB7F),8):PRINT"PCN CURRENT TRACK"
140 RETURN
150 PRINT BIN$(INP(&FB7E),8)
160 RETURN
170 OUT &FB7F,&X01000110:PRINT"(MT MF SK"
180 OUT &FB7F,&X00000000:PRINT"HD US1 US0)"
190 OUT &FB7F,&X00000000:PRINT"C"
200 OUT &FB7F,&X00000000:PRINT"H"
210 OUT &FB7F,&C1:PRINT"R"
220 OUT &FB7F,&X00000010:PRINT"N"
230 OUT &FB7F,&C1:PRINT"EOT"
240 OUT &FB7F,&X00101010:PRINT"GPL"
250 OUT &FB7F,&X11111111:PRINT"DTL"
260 status%=INP(&FB7E):PRINT BIN$(status%,8):if status%=&X11110000 then 280 else if status%=&X11010000 then 340
270 print"BAD STATUS":goto 260
275 a$=inkey$:if a$="" then 275 else 260
280 for a%=1 to 512
290 status%=INP(&FB7E):PRINT BIN$(status%,8):if status% <> &X11110000 then 290
300 print HEX$(INP(&FB7F),2)," (",a%,")"
310 next a%
320 status%=INP(&FB7E):PRINT BIN$(status%,8):if status% <> &X11010000 then 320
330 a$=inkey$:if a$="" then 330
340 PRINT BIN$(INP(&FB7F),8):PRINT"ST0"
350 PRINT BIN$(INP(&FB7F),8):PRINT"ST1"
360 PRINT BIN$(INP(&FB7F),8):PRINT"ST2"
370 PRINT BIN$(INP(&FB7F),8):PRINT"C"
380 PRINT BIN$(INP(&FB7F),8):PRINT"H"
390 PRINT HEX$(INP(&FB7F),2):PRINT"R"
400 PRINT BIN$(INP(&FB7F),8):PRINT"N"
410 RETURN
420 OUT &FB7F,&X01001010:PRINT"(0 MF"
430 OUT &FB7F,&X00000000:PRINT"HD US1 US0)"
440 PRINT BIN$(INP(&FB7F),8):PRINT"ST0"
450 PRINT BIN$(INP(&FB7F),8):PRINT"ST1"
460 PRINT BIN$(INP(&FB7F),8):PRINT"ST2"
470 PRINT BIN$(INP(&FB7F),8):PRINT"C"
480 PRINT BIN$(INP(&FB7F),8):PRINT"H"
490 PRINT HEX$(INP(&FB7F),2):PRINT"R"
500 PRINT BIN$(INP(&FB7F),8):PRINT"N"
510 RETURN
520 OUT &FA7E,0
530 RETURN
540 GOSUB 420:gosub 170
550 END
 
CAT
RUN
GOSUB 150 // STATUS
10000000
 
CAT
RUN
GOSUB 420 // READ_ID
HD US1 US0)
01001001
ST0
00000000
ST1
00000000
ST2
00000000
C
00000000
H
C6 or C1
R
00000010
N
 
READ_ID does run fine in Basic.
 
CAT
RUN
GOSUB 70 // SEEK
HD US1 US0)
TRACK
GOSUB 150
10000001 // drive0 is seeking
GOSUB 110
00100000 // SEEK END
ST0
00000010
PCN CURRENT TRACK
CAT
RUN
GOSUB 40 // RECALIBRATE
HD US1 US0)
TRACK
GOSUB 150
10000001 // drive0 is seeking
GOSUB 110
00100000 // SEEK END
ST0
00000000
PCN CURRENT TRACK
 
It seems that looking at STATUS is needed between SEEK and SENSE_INTERRUPT_STATUS. It's said that SENSE_INTERRUPT_STATUS is needed after SEEK.
 
SEEK too high does return a normal result at SENSE_INTERRUPT_STATUS, RECALIBRATE without disk does return a normal result also at SENSE_INTERRUPT_STATUS. But does result in a fail at READ_ID command,
 
WinAPE READ_ID with too high SEEK :
* 10000000 //ST0 INVALID
* 00100101 //ST1 DATA_ERROR & NO_DATA & MISSING_ADDR
* 00000001 //ST2
* 10001011 //C (too high SEEK)
* 00000000 //H
* C8 //R
* 00000010 //N
 
WinAPE READ_ID without disk inserted :
* 01001000 //ST0 ABNORMAL & NOT_READY
* 00000000 //ST1
* 00000000 //ST2
* 00000010 //C
* 00000000 //H
* C8 //R
* 00000010 //N
 
JEMU READ_ID with too high SEEK :
* 01000000 //ST0 ABNORMAL
* 00000101 //ST1 NO_DATA & MISSING_ADDR
* 00000101 //ST2 SCAN_NOT_SATISFIED & MISSING_ADDR
* 00000101 //C
* 00000101 //H
* 05 //R
* 00000101 //N
 
WinAPE :
 
CAT
RUN
GOTO 540
// READ_ID
HD US1 US0)
01001001
ST0
00000000
ST1
00000000
ST2
00000000
C
00000000
H
C6 or C1
R
00000010
N
// READ_DATA
(MT MF SK
HD US1 US0)
C
H
R
N
EOT
GPL
DTL
11010000 // no EXEC sequence...
01001000 // ... due to NOT READY
ST0
00000000
ST1
00000000
ST2
00000000
C
00000000
H
C1
R
00000010
N
 
...too slow to execute a READ_DATA in Basic.
 
JEMU :
CAT
RUN
GOTO 540
// READ_ID
HD US1 US0)
01001001
ST0
00000000
ST1
00000000
ST2
00000000
C
00000000
H
C6 or C1
R
00000010
N
// READ_DATA
(MT MF SK
HD US1 US0)
C
H
R
N
EOT
GPL
DTL
00010000
BAD STATUS
11010000 // no EXEC sequence...
01000000 // ... due to
ST0
00000101 // NO_DATA & ADDR_MISSING
ST1
00000101 // SCAN_NOT_SATISFIED & ADDR_MISSING
ST2
00000101
C
00000101
H
05
R
00000101
N
 
...too slow to execute a READ_DATA in Basic.
 
ST3SENSE.BAS :
10 OUT &FB7F,&X00000100
20 OUT &FB7F,&X00000001:PRINT"HD US1 US0)"
30 PRINT BIN$(INP(&FB7F),8):PRINT"ST3"
HD US1 US0)
01110001 or 01010001 for drive B, 00000000 on drive A (with US0=0)
ST3
 
==== perl FDC frame decoder ====
Adding a sniffer into UPD765A.java :
writePort(int port, int value){System.out.println("writePort "+Util.hex((byte)port)+" "+Util.hex((byte)value));
readPort(int port) {
System.out.println("writePort "+Util.hex((byte)port)+" "+Util.hex((byte)status));
return status; // just before this
System.out.println("writePort "+Util.hex((byte)port)+" "+Util.hex((byte)data));
return data; // just before that
fdcMessages.pl
# perl fdcMessages.pl < test.dsk.sniffer.txt > test.snif.txt
# perl fdcMessages.pl < orion.dsk.sniffer.txt > orion.snif.txt
use Switch;
my $param_count=0;my $data_read_count=0;my $data_write_count=0;my $result_count=0;
while(my $var = <>){
# print $var."\n";
if ($var =~ /^writePort ([0-9A-F][0-9A-F]) ([0-9A-F][0-9A-F])$/) {
my $addr=$1;my $value=hex($2);
$value_hex=sprintf ("%02X", $value );$value_bin=sprintf ("%08b", $value );
if ($param_count>0) {
$param_count--;
if ($param_count eq 4 or $param_count eq 2) {
print "W$param_count $value_bin $value_hex\n";
} else {
print "W$param_count $value_bin\n";
}
} elsif ($data_write_count>0) {
$data_write_count--;
#print "W $value_hex $data_write_count\n";
if ($data_write_count eq 511) {
print "W $value_hex ";
} elsif ($data_write_count>0) {
print "$value_hex ";
} else {
print "$value_hex\n";
}
} else {
$result_count=0;$data_read_count=0;
print "COMMAND ";
switch($value_bin) {
case /00110$/ {
print "READ_DATA $value_bin\n";
$param_count=8;$data_read_count=512;$result_count=7;}
case /01100$/ {
print "READ_DELETED_DATA $value_bin\n";
$param_count=8;$data_read_count=512;$result_count=7;}
case /00101$/ {
print "WRITE_DATA $value_bin\n";
$param_count=8;$data_write_count=512;$result_count=7;}
case /01001$/ {
print "WRITE_DELETED_DATA $value_bin\n";
$param_count=8;$data_write_count=512;$result_count=7;}
case /00010$/ {
print "READ_DIAGNOSTIC $value_bin\n";
$param_count=8;$data_read_count=512;$result_count=7;}
case /01010$/ {
print "READ_ID $value_bin\n";
$param_count=1;$result_count=7;}
case /01101$/ {
print "WRITE_ID $value_bin (Format Write)\n";
$param_count=5;$result_count=7;}
case /10001$/ {
print "SCAN_EQUAL $value_bin\n";
$param_count=8;$data_read_count=512;$result_count=7;}
case /11001$/ {
print "SCAN_LOW_OR_EQUAL $value_bin\n";
$param_count=8;$data_read_count=512;$result_count=7;}
case /11101$/ {
print "SCAN_HIGH_OR_EQUAL $value_bin\n";
$param_count=8;$data_read_count=512;$result_count=7;}
case /00111$/ {
print "RECALIBRATE $value_bin\n";$param_count=1;}
case /01000$/ {
print "SENSE_INTERRUPT_STATUS $value_bin\n";
$result_count=2;}
case /00011$/ {
print "SPECIFY $value_bin\n";
$param_count=2;}
case /00100$/ {
print "SENSE_DRIVE_STATUS $value_bin\n";
$param_count=1;$result_count=1;}
case /10000$/ {
print "VERSION $value_bin\n";
$result_count=1;}
case /01111$/ {
print "SEEK $value_bin\n";
$param_count=2;}
else {
print "INVALID: $value_bin\n";
$result_count=1;}
}
}
} elsif ($var =~ /^readPort ([0-9A-F][0-9A-F]) ([0-9A-F][0-9A-F])$/) {
my $addr=$1;my $value=hex($2);
$value_hex=sprintf ("%02X", $value );$value_bin=sprintf ("%08b", $value );
if ($addr eq "7E") {
# print "READ_STATUS : $value_bin\n";
} else {
$param_count=0;
if ($data_read_count>0) {
$data_read_count--;
# print "R $value_hex $data_read_count\n";
if ($data_write_count eq 511) {print "R $value_hex ";
} elsif ($data_read_count>0) {print "$value_hex ";
} else {print "$value_hex\n";}
} elsif ($result_count>0) {
$result_count--;
if ($result_count eq 1) {
print "R$result_count $value_bin $value_hex\n";
} else {
print "R$result_count $value_bin\n";
}
} else {
print "R $value_hex (garbage)\n";
}
}
}
}
Result in JavaCPC :
COMMAND READ_DATA 01100110
W7 00000000
W6 00000000
W5 00000000
W4 11000011 C3
W3 00000010
W2 11000011 C3
W1 00101010
W0 11111111
E5 E5....
R6 00000000
R5 00000000
R4 00000000
R3 00000000
R2 00000000
R1 00000001 01 <= not implemented yet like that in FPGAmstrad (one bug found !)
R0 00000010
=== TODO : A X/Y input ===
Done in r005.8.14. Detected as CRTC0 by WakeUp! - "Enjoy the show" message displayed.
 
In r005.8.15. WakeUp! (CRTC0/MEM_wr quick) detected as Emu first time, and after a quick reset, does say detected as CRTC0.
==== DONE : CRTC1 detection ====
[http://cpc.sylvestre.org/technique/technique_coul1.html Les Sucres en Morceaux - Couleurs - 1 - Les couleurs du CPC]
==== TODO DONE : Monochrome OSD ====
Could be great having the OSD in monochrome when monochrome is selected and scanlined when scanline is selected
 
Done in r005.8.14.4
=== TODO : Ethernet ===
Integration of "ethernec.v".
=== TODO DONE : arnoldemu's testbench fdctest ===
arnoldemu's testbench to pass : test/fdctest/fdctest/fdctest.dsk
Have also to fix theses "Bad Command" responses from fdc (it seems that when you don't reach a track, you have to send back the current track instead of this "Bad Command" signal). Test : 30YMD demo, "disk change" message not running correctly, "another disk inserted" is not detected in this demo.
 
==== arnoldemu's testbench results ====
CoreAmstrad r005.8.15
* 27FAIL01/29FAIL01 : read_track6/read_track10 - very big sector size counter not implemented (more than 512B)
* 3DFAIL/45FREEZE : read_data_ov/test_write_ov - using flag simpleDSK.IS_ARNOLDEMU_TESTBENCH=false this test will fail/freeze in final version. It will not be implemented (does slow down some demos : 30YMD/Batman)
* 41FAIL06 : test_write2 - does corrupt the testbench itself (writing a deleted mark in testdisk.dsk file) using flag SDRAM_FAT32_LOADER.IS_ARNOLDEMU_TESTBENCH=false this test will pass in final version, one time :)
* 51FAIL02/52FAIL01 : bad5_cylinder/bad6_cylinder - writing data without data is not implemented
* 59FAIL01 format1 - format command not implemented
* 5EPASS : check_dtl3 - does pass but well to know that a dtl write less than sector_sector_size will not be taken into account (due to write per block of sdcard)
* 60FAIL01 : format2 - format command not implemented (this test is slow)
 
==== TODO : arnoldemu's second testbench ====
 
[http://www.cpctech.org.uk/test.zip http://www.cpctech.org.uk/test.zip] arnold test last update. Folder disc/, tests : "seek, recalibrate, sense interrupt status, sense drive status, write protect"
=== TODO : github migration ===
=== TODO : tapes ===
Do read .CDT files also.
 
I think @ralferoo had already written FPGA code for tape reading for his FPGA CPC. Maybe you can borrow some code from him?
Bryce.
 
=== TODO : welcome VGA signal ===
 
While bootloader is not fully started, do display a lighter screen output (not darker pixels as original screen color CPC depth using more resistors), as it VGA should be nicely centered at each boot. And then after come back to original CPC pixel depth.
 
Some VGA does detect FPGAmstrad resolution just if pixels are ligther, so I turn them lighter during start of engine. Normaly a press into reset button (the one front the sdcard entry) does solve directly this problem (you can also turn on screen before MiST-board with this sort of screens)
 
I tryed also [http://github.com/mist-devel/mist-binaries/tree/master/cores/menu menu core project] with my stupid screen, as it normally I can power on MiST-board before screen for FPGAmstrad (switching core does the stuff here also)
 
Tryed in r005.8.14.4 : lighter pixels during bootload. Also with a full white screen.
 
This solution does not fix the problem of "stupid screen", but reveals something interesting about the defect (next chapter)
 
==== SAMSUNG 16/9 tests ====
Using lighter pixels full white screen during bootload show me that screen doubts between two positions : a perfect centered 4/3 with 6.5 centimeters horizontal border each; and a starting 16/9 at left, crop at 6.5 centimeters left.
 
Without lighter pixels full white screen, the crop of image does change, moving into first displayed characters : in fact in SAMSUNG menu, the position of screen is not 50 50, if you put 50 50 you come back to "lighter pixels full white screen" defect. So here screen begining at first char displayed on screen is a second defect, but a small one, as you just have to set 50 50 in SAMSUNG menu.
 
So back to previous bug : screen doubt between two positions "a perfect centered 4/3 with 6.5 centimeters horizontal border each; and a starting 16/9 at left, crop at 6.5 centimeters left".
When displaying a game, in fact, in found two different case in "perfect centered 4/3" case , this case is not so perfect, it does also doubts between two positions :
 
* one time screen does crop at 6.5 left and right, changing the screen vertical position using menu does translate the image cropping left and right at fix position : 6.5 centimeters fix black border. About extra 1 centimeter pixels : image in middle of image does move, but not the borders at all.
* a second time image does move perfectly (completely/totally) left and right without crop, and if centered has 6.5 black border left and right. This time image seems complete but crushed.
----
1,200
edits