Hallo, Ich glaube es gibt hier einen Spezialisten, der mit an dem Projekt arbeitet. Ich pappe das Verzeichnis mal an als zip. Es geht um das beispiel ANSIest.c wo ich eine Warnung erhalte. Die crt.s Dazei sieht soweit gut aus, sie bildet ja den Startup Code, habe vor 10 Jahren mal selbst eine geschrieben aber ist nicht mehr so präsent. Kompiliert wird mit sdc <filename>, da sollte crt.s mit eingebunden werden. Die beiden crt.s habe ich mit sdasz80 -plosgff -o S190818-R011023_crt0.s und sdasz80 -o S190818_crt0.s kompiliert, in crt0.rel umbenannt und damit die im SDCC Verzeichnis überschrieben. Glaube Philipp heisst der Programmierer aber auch ein gewisser Leo kennt sih damit aus? Kannst Du mal drüber schauen? Die Warnungen scheinen merkwürdig zu sein, denn der Code ist nach der ersten Durchsicht ok. gruss, Throsten E:\Embedded\Z80_MBC2\Backup_SD\SDCC>sdc ANSItest.c ANSItest.c:3: warning 283: function declarator with no prototype No compiler errors. Error: utility srec_cat.exe not found! Nothing to load to the target. E:\Embedded\Z80_MBC2\Backup_SD\SDCC>sdc Blink_MBC2.c Blink_MBC2.c:127: warning 283: function declarator with no prototype Blink_MBC2.c:134: warning 283: function declarator with no prototype No compiler errors. Error: utility srec_cat.exe not found! Nothing to load to the target.
probier mal void main(void) und beim 2. Beispiel char userKey(void); dann verschwinden die Warnungen. Leere Klammern sind ohne Prototypen nicht (mehr) erlaubt. srec_cat.exe liegt nicht in deinem Pfad
Thomas Z. schrieb: > Leere Klammern sind ohne Prototypen > nicht (mehr) erlaubt. ... und zwar schon seit C89 nicht mehr.
Thomas Z. schrieb: > probier mal > void main(void) > > und beim 2. Beispiel > char userKey(void); Da steht nichts anderes drin. srec_cat.exe ist das Hex2Bin Tool von keil. Ist jetzt drin E:\Embedded\Z80_MBC2\SDCC>sdc ANSItest.c ANSItest.c:3: warning 283: function declarator with no prototype No compiler errors. All done! Output executable file (Intel-Hex): out.hex Ok, Warnungen sind weg. Komisch.. früher ging auch while(1); jetzt musst es while(1){}; heissen.
Thorsten M. schrieb: > Da steht nichts anderes drin. dann ist das halt so. Ich frag mich dann aber schon warum du Hilfe suchst
Hier hinter scheinen sich die I/O Ports des MBC2 System zu verbergen. Leider bin ich etwas aus der Materie raus. Der MBC2 benutzt den Atmega als Interface für eine UART, ebenso für einen MC27... als I2C GPIO Port. Leider gibt es keine Doku wie man diese Peripherie ansteuert. // Z80-MBC2 IOS I/O ports definitions __sfr __at 0x00 Exec_port; // IOS Execute Opcode read/write port __sfr __at 0x01 StorOpc_port; // IOS Store Opcode write only port __sfr __at 0x01 SerRx_port; // IOS Serial Rx read only port Damals habe ich das so gemacht // PIO 8255 Special I/O __sfr __at 0x20 PIO8255_PORT_A; __sfr __at 0x21 PIO8255_PORT_B; __sfr __at 0x22 PIO8255_PORT_C; __sfr __at 0x23 PIO8255_CNTRL; Dahinter steckten 4 Register des 8255 am I/O Bus des Z80, die mit speziellen Werten gefüttert werden mussten, d.h. Command Register und Datenregister. Für den MBC2 gibt es leider gar nichts was dahinter steckt. Glaube maximal 256 I/O Adressen sind da möglich. Die Adressierung lief über die unteren Adressleistungen A0-A7.
Thomas Z. schrieb: > dann ist das halt so. Ich frag mich dann aber schon warum du Hilfe > suchst Du hast mir schon geholfen, da fehlte wirklich ein void. Danke!
Thorsten M. schrieb: > Hier hinter scheinen sich die I/O Ports des MBC2 System zu verbergen. > Leider bin ich etwas aus der Materie raus. Der MBC2 benutzt den Atmega > als Interface für eine UART, ebenso für einen MC27... als I2C GPIO Port. > Leider gibt es keine Doku wie man diese Peripherie ansteuert. Du hast dieses "Bios". Wenn Du das aktuelle (auch letzte) "Bios" benutzt (S220718-R290823_IOS-Z80-MBC2.ino), findest Du ab line 892 die Definition der IO-Operationen, die vom ATMEGA ausgefuehrt werden. Ab line 974 findest Du den Zugriff auf den MCP27016:
1 | Wire.beginTransmission(GPIOEXP_ADDR); |
2 | Wire.write(GPIOA_REG); // Select GPIOA |
3 | Wire.write(ioData); // Write value |
4 | Wire.endTransmission(); |
Der Hinweis auf das Datenblatt des MCP27016 darf natuerlich nicht fehlen. Ich kann mich (als Schueler) der Kampf mit dem Datenblatt des 6532 oder 6522 (heute sind das triviale Bausteine) gut erinnern. Gruesse Th.
Danke für den Hinweis! Ich denke diese Tabelle gibt da mehr Aufschluss drüber. Zumindest genug um erstmal eine LED blinken zu lassen. Die scheinen das alles über diese 2 Ports laufen zu lassen und je nachdem welcher Wert reingeschrieben wird bedient der Atmel die passenden Routinen in seiner Firmware. Der hänggt ja auch nur an A0 vom Bus dran, mehr geht ja nicht. Ich frage mich wie der das RAM mit den Images bespielt, denn am Adressbus hängt er nicht dran, nur am Datenbus. __sfr __at 0x00 EXEC_OPCODE; // IOS Execute Opcode read/write port __sfr __at 0x01 STORE_OPCODE; // IOS Store Opcode write only port __sfr __at 0x01 SER_RX; // IOS Serial Rx read only port Danach will ich mcurses als Interface zum VT100 aufsetzen und mit dem SDCC eigene Programme schreiben. // Currently defined Opcodes for I/O write operations: // // Opcode Name Exchanged bytes // ------------------------------------------------- // Opcode 0x00 USER LED 1 // Opcode 0x01 SERIAL TX 1 // Opcode 0x03 GPIOA Write 1 // Opcode 0x04 GPIOB Write 1 // Opcode 0x05 IODIRA Write 1 // Opcode 0x06 IODIRB Write 1 // Opcode 0x07 GPPUA Write 1 // Opcode 0x08 GPPUB Write 1 // Opcode 0x09 SELDISK 1 // Opcode 0x0A SELTRACK 2 // Opcode 0x0B SELSECT 1 // Opcode 0x0C WRITESECT 512 // Opcode 0x0D SETBANK 1 // Opcode 0x0E SETIRQ 1 // Opcode 0x0F SETTICK 1 // Opcode 0x10 SETOPT 1 // Opcode 0x11 SETSPP 1 // Opcode 0x12 WRSPP 1 // Opcode 0xFF No operation 1
Thorsten M. schrieb: > Danke für den Hinweis! > > Ich denke diese Tabelle gibt da mehr Aufschluss drüber. Zumindest genug > um erstmal eine LED blinken zu lassen. Die scheinen das alles über diese > 2 Ports laufen zu lassen und je nachdem welcher Wert reingeschrieben > wird bedient der Atmel die passenden Routinen in seiner Firmware. Im Endeffekt: Ja. Und wenn Du ein wenig bei CP/M 2.2 guckst, wirst Du sehen dass viele CP/M-BIOS-Funktionen direkt implementiert sind. > Der > hänggt ja auch nur an A0 vom Bus dran, mehr geht ja nicht. Ich frage > mich wie der das RAM mit den Images bespielt, denn am Adressbus hängt er > nicht dran, nur am Datenbus. Das ist sehr pfiffig geloest: Da der ATMega die Clock und Reset kontrolliert, kann man die Z80 in einzelnen Clocks betreiben (klappt eigentlich nur bei der CMOS-CPU). Nach dem Reset werden die passenden OPCodes auf den Bus geschrieben, die CPU fuehrt das aus und kann in das reale RAM einschreiben. Wenn Du den Boot-Loader dann in den RAM geschrieben hast, kannst Du neu starten und das Betriebssystem Deiner Wahl starten. Das findet alles bei den Routinen loadByteToRAM(byte value) und loadHL(word value) statt (line 2506ff in S220718-R290823_IOS.MBC2.ino):
1 | void loadByteToRAM(byte value) |
2 | // Load a given byte to RAM using a sequence of two Z80 instructions forced on the data bus.
|
3 | // The RAM_CE2 signal is used to force the RAM in HiZ, so the Atmega can write the needed instruction/data
|
4 | // on the data bus. Controlling the clock signal and knowing exactly how many clocks pulse are required it is possible control the
|
5 | // whole loading process.
|
6 | // In the following "T" are the T-cycles of the Z80 (See the Z80 datashet).
|
7 | // The two instruction are "LD (HL), n" and "INC (HL)".
|
Zu Deinem Wunsch die blaue/weisse/pinke LED blinken zu lassen: Gucke bitte in "Examples with Basic.txt" auf der SD-Card: Du willst ein reines (ohne Betriebssystem) Z80-Programm ausfuehren. Es muesste dann reichen (Pseudo-Code):
1 | OUT 0x1, 0x0 ; Write USER LED |
2 | OUT 0x0, 0x1 ; LED an |
3 | [delay] |
4 | OUT 0x1, 0x0 ; |
5 | OUT 0x0, 0x0 ; LED aus |
Gruesse
>>Im Endeffekt: Ja. Und wenn Du ein wenig bei CP/M 2.2 guckst, wirst Du >>sehen dass viele CP/M-BIOS-Funktionen direkt implementiert sind. Ich hatte damals sowas gemacht. Ginge das auch für die BIOS Routinen, dass man die aus C zugänglich macht mit den entsprechenden Parametern wenn man ihre Adresse kennt? Ich brauche ja eine API zum BIOS. PS: Bin ich froh, dass diese EPROM Brennerei ein Ende hat! Habe noch rund 100 hier. // Absolute Adressen des gesamten RAMs (ohne Stack) und ROMs // Diese Array sind Overlays und benötigen keinen Speicherplatz __at (ROM_START) unsigned char memory[0xffff]; // Kompletter Speicher __at (RAM_SPECIAL) unsigned char ram_info[64]; // Löschsicherer Speicher ROM_START und RAM_SPECIAL waren im crt.s definierte Areas, die ich vom C Program aus verwenden konnte.
1 | .module crt0 ; Modul Name für den Linker |
2 | |
3 | ; Memory Map Adressen der Zeropage (vom Benutzer definierbar) |
4 | ; Definitions |
5 | |
6 | offset .equ 0x4000 ; Basisadresse des Codes |
7 | reset_vector .equ offset |
8 | stack .equ 0xffbf ; Stack |
9 | adr_vec_table .equ offset+0x40 ; Mode 2 Vektor Tabelle für STI Mostek Multi I/O |
10 | adr_copyright .equ offset+0x80 |
11 | heap_size .equ 2048 ; Benutzer definierte Heap Groesse |
12 | |
13 | ; Globale Funktionen und Variablen für das C-Programm |
14 | |
15 | .globl _main |
16 | |
17 | ; Interruptroutinen für den Mostek MK3801 Multi I/O Baustein |
18 | ; Manual STI Baustein MK3801 Figure 7 |
19 | .globl _int_sti_gpi_0 ; General Purpose Interrupt 0 |
20 | .globl _int_sti_gpi_1 ; General Purpose Interrupt 1 |
21 | .globl _int_sti_gpi_2 ; General Purpose Interrupt 2 |
22 | .globl _int_sti_gpi_3 ; General Purpose Interrupt 3 |
23 | .globl _int_sti_timer_d |
24 | .globl _int_sti_timer_c |
25 | .globl _int_sti_gpi_4 ; General Purpose Interrupt 4 |
26 | .globl _int_sti_gpi_5 ; General Purpose Interrupt 5 |
27 | .globl _int_sti_timer_b |
28 | .globl _int_sti_transmit_buffer_empty |
29 | .globl _int_sti_transmit_error |
30 | .globl _int_sti_receive_error |
31 | .globl _int_sti_receive_buffer_full |
32 | .globl _int_sti_timer_a |
33 | .globl _int_sti_gpi_6 ; General Purpose Interrupt 6 |
34 | .globl _int_sti_gpi_7 ; General Purpose Interrupt 7 |
35 | |
36 | .globl l__INITIALIZER |
37 | .globl s__INITIALIZER |
38 | .globl s__INITIALIZED |
39 | |
40 | .globl ___sdcc_heap_init |
41 | .globl _letzte_code_adresse |
42 | .globl _erste_code_adresse |
43 | |
44 | ; ------------------------------------------------------------- |
45 | |
46 | .area _HEADER (ABS) |
47 | ; Reset vector bei Kaltstart und Sprung ins User Programm |
48 | .org reset_vector |
49 | _erste_code_adresse: |
50 | jp init |
51 | |
52 | ; Warmstart mit NMI Interrupt (ohne Speicher loeschen) |
53 | .org reset_vector+3 |
54 | jp init2 |
55 | |
56 | ;/////////////////////////////////////////////////////////// |
57 | ; Tabelle der Mode 2 Int Vektoren auf die Handler Funktionen im C Modul |
58 | ; Reihenfolge beachten !!! Siehe Manual Mostek 3801, Interrupt Tabelle |
59 | .org adr_vec_table |
60 | .dw (_int_sti_gpi_0) |
61 | .dw (_int_sti_gpi_1) |
62 | .dw (_int_sti_gpi_2) |
63 | .dw (_int_sti_gpi_3) |
64 | .dw (_int_sti_timer_d) |
65 | .dw (_int_sti_timer_c) |
66 | .dw (_int_sti_gpi_4) |
67 | .dw (_int_sti_gpi_5) |
68 | .dw (_int_sti_timer_b) |
69 | .dw (_int_sti_transmit_error) |
70 | .dw (_int_sti_transmit_buffer_empty) |
71 | .dw (_int_sti_receive_error) |
72 | .dw (_int_sti_receive_buffer_full) |
73 | .dw (_int_sti_timer_a) |
74 | .dw (_int_sti_gpi_6) |
75 | .dw (_int_sti_gpi_7) |
76 | |
77 | .org adr_copyright |
78 | .asciz "Z80/MK3801 System" |
79 | |
80 | ;/////////////////////////////////////////////////////////// |
81 | ; Anordung der Segmente fuer den Linker, ab hier nur relative |
82 | ; Adressen |
83 | |
84 | .area _CODE |
85 | .area _INITIALIZER |
86 | .area _HOME |
87 | .area _GSINIT |
88 | .area _GSFINAL |
89 | .area _DATA |
90 | .area _INITIALIZED |
91 | .area _BSEG |
92 | .area _BSS |
93 | .area _HEAP |
94 | |
95 | ; --- Defintion der Heap Groesse |
96 | __sdcc_heap_start:: |
97 | .ds heap_size |
98 | |
99 | .area _HEAP_END |
100 | __sdcc_heap_end:: |
101 | .ds 1 |
102 | |
103 | ;/////////////////////////////////////////////////////////// |
104 | ;; ------- Start des Hauptprogramms nach der Zeropage ----------- |
105 | |
106 | .area _CODE |
107 | init: |
108 | init2: |
109 | ld sp,#stack ;; Stack an Spitze des RAM legen |
110 | call gsinit ;; Static Variablen init |
111 | call _main ;; Hauptprogramm aufrufen |
112 | endlos: |
113 | halt
|
114 | jr endlos |
115 | |
116 | .area _GSINIT |
117 | |
118 | gsinit: |
119 | |
120 | ; Initialisiere den HEAP |
121 | call ___sdcc_heap_init |
122 | |
123 | ; Initialisiere globale Variablen im RAM |
124 | ld bc, #l__INITIALIZER |
125 | ld a, b |
126 | or a, c |
127 | jr Z, weiter |
128 | ld de, #s__INITIALIZED |
129 | ld hl, #s__INITIALIZER |
130 | ldir
|
131 | |
132 | weiter: |
133 | |
134 | ; // Hier muss ein ret rein |
135 | .area _GSFINAL |
136 | ret
|
137 | ;Markiert das Ende des Programmes |
138 | .asciz "Z80 END OF PROGRAM" |
139 | _letzte_code_adresse: |
Ich verstehe nicht Dein Goal nicht: Willst Du ein CP/M-Programm schreiben (dann hast Du natuerlich alle Moeglichkeiten, dazu musst Du aber das BIOS haben), dann kannst Du die BIOS-Calls wie folgt benutzen (aus: http://www.gaby.de/cpm/manuals/archive/cpm22htm/ch5.htm)
1 | As mentioned above, access to the FDOS functions is accomplished by passing a function number and information address through the primary point at location BOOT+0005H. In general, the function number is passed in register C with the information address in the double byte pair DE. Single byte values are returned in register A, with double byte values returned in HL, a zero value is returned when the function number is out of range. For reasons of compatibility, register A = L and register B = H upon return in all cases. |
Aber gerade die Unabhaengigkeit von den festen Adressen war ja genau der grosse Fortschritt bei CP/M (und die Modularitaet der Teile des Betriebssystemes). Alternativ wirklich ohne alles: Kleines Z80-Assembler, Start bei 0x0000 (Reset0) und gut ist. Beides ist Moeglich. Gruesse Th.
Thomas W. schrieb: > Ich verstehe nicht Dein Goal nicht: Willst Du ein CP/M-Programm > schreiben (dann hast Du natuerlich alle Moeglichkeiten, dazu musst Du > aber das BIOS haben), dann kannst Du die BIOS-Calls wie folgt benutzen The principal entry point to the FDOS is at location BOOT+0005H (normally 0005H) where a jump to BASE is found. As mentioned above, access to the FDOS functions is accomplished by passing a function number and information address through the primary point at location BOOT+0005H Danke, das reicht schon. Ich habe in den 90iger Asm Programme für den X86 geschrieben da musste man den INT21h beedienen für DOS und einen anderen fürs BIOS. Stand alles im PC Intern. Ich brauche nur das VT100 Interface, den ganzen Low Level Disk Kram tue ich mir nicht an. Und ich muss mir ein C Konstrukt basteln, was die Funktionen anspringt, da ich auf Assembler verzichten will. Also eine C Funktion, die vielleicht etwas Inline Assembler hat die das managed. char MyFunc(int parameter) { __asm Lade HIbyte(parameter) __asm Lade LObyte(parameter) CALL BDOS return (Rückgabewerte) } Habe zwar eine C Lib mcurses, die VT100 bedienen kann aber die müsste mein Programm dann mitschleppen, dabei gibt es das ja alles schon im BDOS. Alternativ geht natürlich auch mbasic von Grant Serle, das sich auch kompilieren lässt zu einem COM File.ö Zusammen mit dem autostart Mechanismus kann man so ein Programm starten und zb die GPIO Leiste bedienen, das ist alls schon drin mit dem OUT und IN Befehlen. Allerdings ist die Editor Funktion nicht komfortabel, das würde ich alles schon gern am PC machen und dann hochladen als Text oder als Kompilat. Copy & Paste klappen aber im Terminalfenster, d.h. mans spart sich das mühsame Eintippen.
Thorsten M. schrieb: > > Habe zwar eine C Lib mcurses, die VT100 bedienen kann aber die müsste > mein Programm dann mitschleppen, dabei gibt es das ja alles schon im > BDOS. Noe. BDOS steht fuer Basic DISK Operating System, ja, es hat auch Character I/O, RAW I/O und buffered Read and Write (praktisch ein PrintString), aber curses bietet deutlich mehr. Insbesondere Cursor-Control ist Deine Aufgabe. Es sind ja jetzt vierzig Jahre her, es kann sein, dass sich Deine Erinnerungen etwas vermischen? Kannst Du Dich noch an die ellenlangen Listen von Terminal-Codes wg. Cursor-Up, -Down oder Erase Line erinnern? Oder das Elend mit den Floppy-Disk-Formaten? Jeder hatte seine eigene Wurst?
Thomas W. schrieb: > Es sind ja jetzt vierzig Jahre her, es kann sein, dass sich Deine > Erinnerungen etwas vermischen? Kannst Du Dich noch an die ellenlangen > Listen von Terminal-Codes wg. Cursor-Up, -Down oder Erase Line erinnern? In der mcurses von Frank (UKW) ist man davon entbunden, die Routinen bauen die ESC Sequenzen einfach ein. Es geht ja nur um Textfelder, Cursor zurück, poitionierend usw.
Thorsten M. schrieb: > In der mcurses von Frank (UKW) ist man davon entbunden, die Routinen > bauen die ESC Sequenzen einfach ein. Hier noch ergänzend die Doku dazu: MCURSES
:
Bearbeitet durch Moderator
Thorsten M. schrieb: > Die beiden crt.s habe ich mit > > sdasz80 -plosgff -o S190818-R011023_crt0.s und > sdasz80 -o S190818_crt0.s > > kompiliert, in crt0.rel umbenannt und damit die im SDCC Verzeichnis > überschrieben. Das übliche vorgehen ist, die crt0.rel von SDCC zu lassen, wie sie ist, die eigene "crt0.rel" (muss nicht notwendigerweise so heißen) beim Linkeraufruf als erste .rel anzugeben, und --no-std-crt0 zu verwenden, also z.B.: sdcc --no-std-crt0 crt0.rel dhry_1.rel dhry_2.rel portme.rel -o image.ihx P.S.: Als Beispielprogramm für SDCC fürs MBC2-Board sollte sich z.B. der Dhrystone hier eignen: https://sourceforge.net/p/sdcc/code/HEAD/tree/trunk/sdcc-extra/historygraphs/dhrystone-z80/
Thorsten M. schrieb: > Komisch.. früher ging auch while(1); jetzt musst > es while(1){}; heissen. Welches Problem tritt bei while(1); auf? Das sollte weiterhin funktionieren (und tut es bei mir mit aktuellem SDCC auch).
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.