From f8522967cc6a6f0a019f6a95363bfcd8c785b42f Mon Sep 17 00:00:00 2001 From: Sandy Pleyte Date: Tue, 7 Nov 2017 19:16:41 +0100 Subject: [PATCH] Latest version of the documents --- README.md | 312 ++--- .../00/machinetaal.md | 0 .../01/machinetaal_2.md | 0 future_disk/02/cirkels_in_ml.md | 173 +++ future_disk/02/machinetaal_3.md | 227 ++++ future_disk/03/machinetaal_4.md | 221 ++++ future_disk/04/machinetaal_5.md | 287 +++++ future_disk/05/machinetaal_6.md | 168 +++ future_disk/05/special_effects_basic.md | 216 ++++ future_disk/06/machinetaal_7.md | 203 ++++ future_disk/06/special_effects_basic_2.md | 221 ++++ future_disk/07/machinetaal_8.md | 229 ++++ future_disk/07/special_effects_basic_3.md | 218 ++++ future_disk/075/machinetaal_cursus_9.md | 204 ++++ future_disk/075/special_effects_basic_4.md | 593 +++++++++ future_disk/075/turbo-r_basic.md | 184 +++ future_disk/10/machinetaal_10.md | 273 +++++ future_disk/10/special_effects_basic_5.md | 174 +++ future_disk/11/machinetaal_11.md | 128 ++ future_disk/11/pascal_1.md | 51 + future_disk/12/pascal_2.md | 158 +++ future_disk/12/special_effects_basic_5.md | 205 ++++ future_disk/13/machinetaal_12.md | 145 +++ future_disk/13/pascal_3.md | 153 +++ future_disk/14/pascal_4.md | 150 +++ future_disk/15/data_compressie.md | 103 ++ .../15/looplichtje.md | 0 future_disk/15/pascal_5.md | 85 ++ future_disk/15/the_2+_corner.md | 118 ++ future_disk/17/basic_cursus_6.md | 117 ++ future_disk/17/data_compressie_2.md | 141 +++ future_disk/17/pascal_6.md | 245 ++++ future_disk/18/data_compressie_3.md | 316 +++++ future_disk/18/mooblaster_music_cursus.md | 204 ++++ future_disk/18/pascal_7.md | 148 +++ future_disk/18/undocumented_z80_code.md | 57 + future_disk/19/basic_cursus_8.md | 77 ++ future_disk/19/basic_voor_beginners.md | 89 ++ future_disk/19/looplichtjes_2.md | 39 + future_disk/19/mcode_special_1.md | 181 +++ future_disk/19/moonblaster_music_cursus_2.md | 90 ++ future_disk/19/msx2+_schermen_in_basic.md | 169 +++ future_disk/19/pascal_8.md | 382 ++++++ future_disk/20/data_compressie_4.md | 29 + future_disk/20/moonblaster_music_cursus_3.md | 158 +++ future_disk/20/muizen_in_basic.md | 101 ++ future_disk/20/turbo-r_basic.md | 177 +++ future_disk/21/call_kanji.md | 178 +++ .../21/Ledjes.md => future_disk/21/ledjes.md | 0 future_disk/21/mcode_special_2.md | 202 ++++ future_disk/21/moonblaster_music_cursus_4.md | 101 ++ .../Recursie.md => future_disk/21/recursie.md | 0 future_disk/21/screen_12.md | 75 ++ future_disk/22/data_compressie_5.md | 1055 +++++++++++++++++ future_disk/22/moonblaster_music_cursus_5.md | 324 +++++ future_disk/23/mcode_special_3.md | 256 ++++ future_disk/24/2+_schermen.md | 149 +++ future_disk/24/v9958_in_ml.md | 79 ++ future_disk/25/clock_chip.md | 154 +++ future_disk/25/mcode_special_4.md | 282 +++++ future_disk/25/msx-dos2_deel_1.md | 193 +++ future_disk/27/mcode_special_5.md | 119 ++ .../Rotatie.md => future_disk/27/rotatie.md | 0 future_disk/28/msx-dos2_deel_2.md | 94 ++ future_disk/28/msx-dos2_deel_3.md | 96 ++ future_disk/28/the_pcm_sample_processor.md | 102 ++ future_disk/30/advanced_basic.md | 90 ++ future_disk/30/assembly_voor_beginners.md | 106 ++ future_disk/30/paint_in_ml.md | 78 ++ future_disk/31/advanced_basic_2.md | 221 ++++ future_disk/31/disk_io_in_basic.md | 236 ++++ future_disk/32/pascal_cursus_1_en.md | 103 ++ future_disk/32/pascal_cursus_1_nl.md | 156 +++ future_disk/32/pascal_cursus_2_en.md | 83 ++ future_disk/32/pascal_cursus_2_nl.md | 159 +++ future_disk/32/screen_4.md | 194 +++ future_disk/33/advanced_basic_3.md | 92 ++ future_disk/33/assembly_cursus_2.md | 109 ++ future_disk/33/bits_en_bull.md | 259 ++++ future_disk/33/pascal_3.md | 150 +++ future_disk/33/pascal_4.md | 148 +++ {Future Disk => future_disk}/34/Mathpack.md | 0 future_disk/34/advanced_basic_4.md | 150 +++ future_disk/34/assembly_cursus_3.md | 186 +++ future_disk/34/pascal_5.md | 333 ++++++ future_disk/35/assembly_cursus_4.md | 165 +++ future_disk/35/copy_in_basic.md | 82 ++ .../35/datacompressie.md | 0 future_disk/35/pascal_7.md | 146 +++ future_disk/35/pascal_8.md | 381 ++++++ future_disk/36/advanced_basic_5.md | 108 ++ future_disk/36/assembly_cursus_5.md | 110 ++ future_disk/36/datacompressie_2.md | 145 +++ future_disk/36/mathpack_2.md | 109 ++ future_disk/36/recursie_2.md | 121 ++ future_disk/36/rom_images_laden.md | 112 ++ future_disk/37/advanced_basic_6.md | 102 ++ future_disk/37/assembly_cursus_6.md | 830 +++++++++++++ future_disk/37/mathpack_3.md | 91 ++ future_disk/38/assembly_cursus_7.md | 138 +++ future_disk/40/assembly_cursus_8.md | 63 + future_disk/40/schuiven_en_roteren.md | 131 ++ {Future Disk => future_disk}/42/Lijntjes.md | 0 future_disk/42/assembly_cursus_9.md | 453 +++++++ .../1/R800.md | 0 sunrise_special/1/disk_cursus_special_1.md | 647 ++++++++++ sunrise_special/1/geheugen_tellen.md | 312 +++++ sunrise_special/1/het_rel_file_formaat.md | 60 + sunrise_special/1/hybride_programmeren.md | 647 ++++++++++ sunrise_special/1/memman_2.3_intro.md | 391 ++++++ sunrise_special/1/memman_2.3_specificaties.md | 641 ++++++++++ sunrise_special/1/msx_assemblers.md | 274 +++++ sunrise_special/1/muis_uitlezen.md | 216 ++++ sunrise_special/1/pointers_in_pascal.md | 178 +++ sunrise_special/1/recursief_programmeren.md | 150 +++ sunrise_special/1/rel_assembleren.md | 173 +++ sunrise_special/1/set_scroll_in_basic.md | 108 ++ .../1/te_zachte_psg_bij_de_nms_8250_55_80.md | 36 + sunrise_special/1/track_0_op_de_turbo-r.md | 78 ++ {Sunrise Special => sunrise_special}/2/CDD.md | 0 .../2/Redirection.md | 0 .../2/blinkmode.md | 0 sunrise_special/2/cursus_dd-graph.md | 448 +++++++ sunrise_special/2/geheugen_schakelen.md | 480 ++++++++ .../2/interrupt_service_routines.md | 801 +++++++++++++ .../Ledjes.md => sunrise_special/2/ledjes.md | 0 .../2/macro_commandos_met_gen80.md | 258 ++++ sunrise_special/2/memman_2.42.md | 76 ++ sunrise_special/2/msx-dos_2.31.md | 186 +++ .../msx-dos_2_voor_machinetaalprogrammeurs.md | 428 +++++++ sunrise_special/2/pauze_toets.md | 258 ++++ sunrise_special/2/pcm_routines_van_de_bios.md | 84 ++ sunrise_special/2/pcm_sampler.md | 760 ++++++++++++ sunrise_special/2/programmeer_taal_c.md | 587 +++++++++ sunrise_special/2/programmeer_taal_c_2.md | 272 +++++ .../2/rechtstreeks_via_pcm_afspelen.md | 123 ++ .../2/resource.md | 0 sunrise_special/2/stereo_scc.md | 20 + sunrise_special/2/vdp_cursus_1.md | 418 +++++++ sunrise_special/2/vdp_cursus_2.md | 455 +++++++ .../3/de_archeologie_van_de_msx.md | 222 ++++ .../3/de_programmeertaal_c_deel_3.md | 616 ++++++++++ .../3/de_programmeertaal_c_deel_4.md | 464 ++++++++ sunrise_special/3/file_handles.md | 185 +++ sunrise_special/3/getallen_printen.md | 213 ++++ .../3/getdisk.md | 0 sunrise_special/3/hybride_call_commandos.md | 567 +++++++++ sunrise_special/3/memman_problemen.md | 242 ++++ sunrise_special/3/programmeren_sample_chip.md | 176 +++ sunrise_special/3/scrollen_in_kun_basic.md | 72 ++ sunrise_special/3/tsr_change_cpu.md | 236 ++++ sunrise_special/3/tsr_development_kit.md | 91 ++ sunrise_special/3/tsr_volume_input_meter.md | 316 +++++ sunrise_special/3/turbo-r_systeemcounter.md | 153 +++ sunrise_special/3/turbo_pascal_patch.md | 76 ++ sunrise_special/3/vdp_commando_registers.md | 326 +++++ sunrise_special/3/vdp_cursus_3.md | 274 +++++ sunrise_special/3/vdp_cursus_4.md | 384 ++++++ sunrise_special/3/werken_met_ascii_c.md | 167 +++ sunrise_special/4/BDOS foutafhandeling.md | 186 +++ sunrise_special/4/Boot2com.md | 51 + sunrise_special/4/Circle.md | 206 ++++ sunrise_special/4/Copdisk.md | 27 + sunrise_special/4/DOS2 Batchfiles.md | 381 ++++++ .../4/De Programmeertaal C deel 5.md | 679 +++++++++++ sunrise_special/4/Dirsort.md | 192 +++ sunrise_special/4/Easy BDOS.md | 403 +++++++ sunrise_special/4/GetDisk 2.0.md | 126 ++ sunrise_special/4/HD Indelen.md | 110 ++ sunrise_special/4/HEX Printen.md | 75 ++ sunrise_special/4/Index registers.md | 198 ++++ sunrise_special/4/Kun-Basic Cursus.md | 435 +++++++ sunrise_special/4/MBScan.md | 76 ++ sunrise_special/4/MSX Audio.md | 95 ++ sunrise_special/4/NTM Coordin.md | 204 ++++ sunrise_special/4/PCM Rechtstreeks.md | 346 ++++++ sunrise_special/4/Print routine.md | 203 ++++ sunrise_special/4/R800 Drive.md | 34 + sunrise_special/4/Random.md | 181 +++ sunrise_special/4/Read to kana.md | 20 + sunrise_special/4/Tweede drive aan turbo r.md | 36 + sunrise_special/4/V9990 Specificaties.md | 128 ++ sunrise_special/4/V9990.md | 158 +++ sunrise_special/4/VDP Cursus 5.md | 166 +++ sunrise_special/4/VDP Curus 6.md | 358 ++++++ .../4/Werken met ASCII C deel 2.md | 346 ++++++ sunrise_special/5/C Cursus deel 6.md | 338 ++++++ sunrise_special/5/Fout vertaler.md | 26 + sunrise_special/5/Frequenty analyzer.md | 20 + .../5/Gestruktureerd programmeren.md | 264 +++++ sunrise_special/5/HD op write protected.md | 21 + sunrise_special/5/IO Interface.md | 292 +++++ sunrise_special/5/Interrupt mode 2.md | 139 +++ .../5/MIDI een taal in beweging.md | 463 ++++++++ .../5/Make and change directory.md | 34 + sunrise_special/5/Memman Bugje.md | 186 +++ sunrise_special/5/Picture packer.md | 104 ++ sunrise_special/5/R800 rom ram lezen.md | 53 + sunrise_special/5/Rekenen op Z80.md | 611 ++++++++++ sunrise_special/5/Shem.md | 53 + .../5/Software projecten deel 1.md | 450 +++++++ sunrise_special/5/Spelontwerp 2.md | 162 +++ sunrise_special/5/Sprites in ML deel 2.md | 273 +++++ sunrise_special/5/To.md | 141 +++ sunrise_special/5/Turbo Loader.md | 305 +++++ sunrise_special/5/Uncall.md | 23 + sunrise_special/5/VDP Cursus 7.md | 421 +++++++ sunrise_special/5/VDP Cursus 8.md | 502 ++++++++ sunrise_special/5/VDP Cursus 9.md | 187 +++ .../5/Werken met ASCII C deel 3.md | 293 +++++ sunrise_special/5/Z80dis.md | 367 ++++++ sunrise_special/6/Bepalen van nulpunten.md | 209 ++++ sunrise_special/6/Clock en batterij memory.md | 427 +++++++ sunrise_special/6/Cursus modula deel 1.md | 282 +++++ .../6/Een muis met een staartje.md | 354 ++++++ sunrise_special/6/Files voor MSX View.md | 23 + ...estruktureerd programmeren in ML deel 2.md | 205 ++++ sunrise_special/6/HDSpeed.md | 49 + sunrise_special/6/Luna.md | 191 +++ sunrise_special/6/MSX View.md | 102 ++ sunrise_special/6/MSX2 Blink besturing.md | 304 +++++ .../6/Memman TSR Development Kit.md | 81 ++ .../6/Memman in theorie en praktijk.md | 241 ++++ sunrise_special/6/Memory Mapper.md | 272 +++++ sunrise_special/6/Modula2.md | 85 ++ .../6/SCC geluid via stereo pak.md | 28 + sunrise_special/6/Sprites in de praktijk.md | 156 +++ sunrise_special/6/Subdirs onder DOS1.md | 156 +++ sunrise_special/6/Turbo Modula-2.md | 130 ++ sunrise_special/6/Valburg systeem.md | 146 +++ sunrise_special/6/Waarom Modula2.md | 109 ++ sunrise_special/7/Barcode.md | 238 ++++ sunrise_special/7/CMD Mode V9958.md | 148 +++ sunrise_special/7/Diskette elende.md | 299 +++++ sunrise_special/7/Erix Driver.md | 399 +++++++ sunrise_special/7/Gestructureerd ML deel 3.md | 129 ++ sunrise_special/7/Harddisks op MSX.md | 336 ++++++ sunrise_special/7/Interfacing RS232.md | 188 +++ sunrise_special/7/Luna.md | 197 +++ sunrise_special/7/ML Technieken.md | 481 ++++++++ sunrise_special/7/Midi Cursus.md | 563 +++++++++ sunrise_special/7/Music Module naar 256k.md | 65 + sunrise_special/7/Nogmaals BDOS routines.md | 497 ++++++++ sunrise_special/7/Score in ML.md | 394 ++++++ .../7/Toetsenborden en microbiologie.md | 113 ++ sunrise_special/7/VDP Cursus 11.md | 334 ++++++ sunrise_special/7/VDP Cursus 12.md | 314 +++++ sunrise_special/7/VDP Cursus 13.md | 477 ++++++++ sunrise_special/7/VDP Cursus 14.md | 174 +++ sunrise_special/7/VDP Cursus 15.md | 405 +++++++ sunrise_special/7/VDP Cursus 16.md | 251 ++++ sunrise_special/7/Valburg reactie.md | 257 ++++ 252 files changed, 52664 insertions(+), 156 deletions(-) rename Future Disk/00/Machinetaal.md => future_disk/00/machinetaal.md (100%) rename Future Disk/01/Machinetaal 2.md => future_disk/01/machinetaal_2.md (100%) create mode 100644 future_disk/02/cirkels_in_ml.md create mode 100644 future_disk/02/machinetaal_3.md create mode 100644 future_disk/03/machinetaal_4.md create mode 100644 future_disk/04/machinetaal_5.md create mode 100644 future_disk/05/machinetaal_6.md create mode 100644 future_disk/05/special_effects_basic.md create mode 100644 future_disk/06/machinetaal_7.md create mode 100644 future_disk/06/special_effects_basic_2.md create mode 100644 future_disk/07/machinetaal_8.md create mode 100644 future_disk/07/special_effects_basic_3.md create mode 100644 future_disk/075/machinetaal_cursus_9.md create mode 100644 future_disk/075/special_effects_basic_4.md create mode 100644 future_disk/075/turbo-r_basic.md create mode 100644 future_disk/10/machinetaal_10.md create mode 100644 future_disk/10/special_effects_basic_5.md create mode 100644 future_disk/11/machinetaal_11.md create mode 100644 future_disk/11/pascal_1.md create mode 100644 future_disk/12/pascal_2.md create mode 100644 future_disk/12/special_effects_basic_5.md create mode 100644 future_disk/13/machinetaal_12.md create mode 100644 future_disk/13/pascal_3.md create mode 100644 future_disk/14/pascal_4.md create mode 100644 future_disk/15/data_compressie.md rename Future Disk/15/Looplichtje.md => future_disk/15/looplichtje.md (100%) create mode 100644 future_disk/15/pascal_5.md create mode 100644 future_disk/15/the_2+_corner.md create mode 100644 future_disk/17/basic_cursus_6.md create mode 100644 future_disk/17/data_compressie_2.md create mode 100644 future_disk/17/pascal_6.md create mode 100644 future_disk/18/data_compressie_3.md create mode 100644 future_disk/18/mooblaster_music_cursus.md create mode 100644 future_disk/18/pascal_7.md create mode 100644 future_disk/18/undocumented_z80_code.md create mode 100644 future_disk/19/basic_cursus_8.md create mode 100644 future_disk/19/basic_voor_beginners.md create mode 100644 future_disk/19/looplichtjes_2.md create mode 100644 future_disk/19/mcode_special_1.md create mode 100644 future_disk/19/moonblaster_music_cursus_2.md create mode 100644 future_disk/19/msx2+_schermen_in_basic.md create mode 100644 future_disk/19/pascal_8.md create mode 100644 future_disk/20/data_compressie_4.md create mode 100644 future_disk/20/moonblaster_music_cursus_3.md create mode 100644 future_disk/20/muizen_in_basic.md create mode 100644 future_disk/20/turbo-r_basic.md create mode 100644 future_disk/21/call_kanji.md rename Future Disk/21/Ledjes.md => future_disk/21/ledjes.md (100%) create mode 100644 future_disk/21/mcode_special_2.md create mode 100644 future_disk/21/moonblaster_music_cursus_4.md rename Future Disk/21/Recursie.md => future_disk/21/recursie.md (100%) create mode 100644 future_disk/21/screen_12.md create mode 100644 future_disk/22/data_compressie_5.md create mode 100644 future_disk/22/moonblaster_music_cursus_5.md create mode 100644 future_disk/23/mcode_special_3.md create mode 100644 future_disk/24/2+_schermen.md create mode 100644 future_disk/24/v9958_in_ml.md create mode 100644 future_disk/25/clock_chip.md create mode 100644 future_disk/25/mcode_special_4.md create mode 100644 future_disk/25/msx-dos2_deel_1.md create mode 100644 future_disk/27/mcode_special_5.md rename Future Disk/27/Rotatie.md => future_disk/27/rotatie.md (100%) create mode 100644 future_disk/28/msx-dos2_deel_2.md create mode 100644 future_disk/28/msx-dos2_deel_3.md create mode 100644 future_disk/28/the_pcm_sample_processor.md create mode 100644 future_disk/30/advanced_basic.md create mode 100644 future_disk/30/assembly_voor_beginners.md create mode 100644 future_disk/30/paint_in_ml.md create mode 100644 future_disk/31/advanced_basic_2.md create mode 100644 future_disk/31/disk_io_in_basic.md create mode 100644 future_disk/32/pascal_cursus_1_en.md create mode 100644 future_disk/32/pascal_cursus_1_nl.md create mode 100644 future_disk/32/pascal_cursus_2_en.md create mode 100644 future_disk/32/pascal_cursus_2_nl.md create mode 100644 future_disk/32/screen_4.md create mode 100644 future_disk/33/advanced_basic_3.md create mode 100644 future_disk/33/assembly_cursus_2.md create mode 100644 future_disk/33/bits_en_bull.md create mode 100644 future_disk/33/pascal_3.md create mode 100644 future_disk/33/pascal_4.md rename {Future Disk => future_disk}/34/Mathpack.md (100%) create mode 100644 future_disk/34/advanced_basic_4.md create mode 100644 future_disk/34/assembly_cursus_3.md create mode 100644 future_disk/34/pascal_5.md create mode 100644 future_disk/35/assembly_cursus_4.md create mode 100644 future_disk/35/copy_in_basic.md rename Future Disk/35/Datacompressie.md => future_disk/35/datacompressie.md (100%) create mode 100644 future_disk/35/pascal_7.md create mode 100644 future_disk/35/pascal_8.md create mode 100644 future_disk/36/advanced_basic_5.md create mode 100644 future_disk/36/assembly_cursus_5.md create mode 100644 future_disk/36/datacompressie_2.md create mode 100644 future_disk/36/mathpack_2.md create mode 100644 future_disk/36/recursie_2.md create mode 100644 future_disk/36/rom_images_laden.md create mode 100644 future_disk/37/advanced_basic_6.md create mode 100644 future_disk/37/assembly_cursus_6.md create mode 100644 future_disk/37/mathpack_3.md create mode 100644 future_disk/38/assembly_cursus_7.md create mode 100644 future_disk/40/assembly_cursus_8.md create mode 100644 future_disk/40/schuiven_en_roteren.md rename {Future Disk => future_disk}/42/Lijntjes.md (100%) create mode 100644 future_disk/42/assembly_cursus_9.md rename {Sunrise Special => sunrise_special}/1/R800.md (100%) create mode 100644 sunrise_special/1/disk_cursus_special_1.md create mode 100644 sunrise_special/1/geheugen_tellen.md create mode 100644 sunrise_special/1/het_rel_file_formaat.md create mode 100644 sunrise_special/1/hybride_programmeren.md create mode 100644 sunrise_special/1/memman_2.3_intro.md create mode 100644 sunrise_special/1/memman_2.3_specificaties.md create mode 100644 sunrise_special/1/msx_assemblers.md create mode 100644 sunrise_special/1/muis_uitlezen.md create mode 100644 sunrise_special/1/pointers_in_pascal.md create mode 100644 sunrise_special/1/recursief_programmeren.md create mode 100644 sunrise_special/1/rel_assembleren.md create mode 100644 sunrise_special/1/set_scroll_in_basic.md create mode 100644 sunrise_special/1/te_zachte_psg_bij_de_nms_8250_55_80.md create mode 100644 sunrise_special/1/track_0_op_de_turbo-r.md rename {Sunrise Special => sunrise_special}/2/CDD.md (100%) rename {Sunrise Special => sunrise_special}/2/Redirection.md (100%) rename Sunrise Special/2/Blinkmode.md => sunrise_special/2/blinkmode.md (100%) create mode 100644 sunrise_special/2/cursus_dd-graph.md create mode 100644 sunrise_special/2/geheugen_schakelen.md create mode 100644 sunrise_special/2/interrupt_service_routines.md rename Sunrise Special/2/Ledjes.md => sunrise_special/2/ledjes.md (100%) create mode 100644 sunrise_special/2/macro_commandos_met_gen80.md create mode 100644 sunrise_special/2/memman_2.42.md create mode 100644 sunrise_special/2/msx-dos_2.31.md create mode 100644 sunrise_special/2/msx-dos_2_voor_machinetaalprogrammeurs.md create mode 100644 sunrise_special/2/pauze_toets.md create mode 100644 sunrise_special/2/pcm_routines_van_de_bios.md create mode 100644 sunrise_special/2/pcm_sampler.md create mode 100644 sunrise_special/2/programmeer_taal_c.md create mode 100644 sunrise_special/2/programmeer_taal_c_2.md create mode 100644 sunrise_special/2/rechtstreeks_via_pcm_afspelen.md rename Sunrise Special/2/Resource.md => sunrise_special/2/resource.md (100%) create mode 100644 sunrise_special/2/stereo_scc.md create mode 100644 sunrise_special/2/vdp_cursus_1.md create mode 100644 sunrise_special/2/vdp_cursus_2.md create mode 100644 sunrise_special/3/de_archeologie_van_de_msx.md create mode 100644 sunrise_special/3/de_programmeertaal_c_deel_3.md create mode 100644 sunrise_special/3/de_programmeertaal_c_deel_4.md create mode 100644 sunrise_special/3/file_handles.md create mode 100644 sunrise_special/3/getallen_printen.md rename Sunrise Special/3/Getdisk.md => sunrise_special/3/getdisk.md (100%) create mode 100644 sunrise_special/3/hybride_call_commandos.md create mode 100644 sunrise_special/3/memman_problemen.md create mode 100644 sunrise_special/3/programmeren_sample_chip.md create mode 100644 sunrise_special/3/scrollen_in_kun_basic.md create mode 100644 sunrise_special/3/tsr_change_cpu.md create mode 100644 sunrise_special/3/tsr_development_kit.md create mode 100644 sunrise_special/3/tsr_volume_input_meter.md create mode 100644 sunrise_special/3/turbo-r_systeemcounter.md create mode 100644 sunrise_special/3/turbo_pascal_patch.md create mode 100644 sunrise_special/3/vdp_commando_registers.md create mode 100644 sunrise_special/3/vdp_cursus_3.md create mode 100644 sunrise_special/3/vdp_cursus_4.md create mode 100644 sunrise_special/3/werken_met_ascii_c.md create mode 100644 sunrise_special/4/BDOS foutafhandeling.md create mode 100644 sunrise_special/4/Boot2com.md create mode 100644 sunrise_special/4/Circle.md create mode 100644 sunrise_special/4/Copdisk.md create mode 100644 sunrise_special/4/DOS2 Batchfiles.md create mode 100644 sunrise_special/4/De Programmeertaal C deel 5.md create mode 100644 sunrise_special/4/Dirsort.md create mode 100644 sunrise_special/4/Easy BDOS.md create mode 100644 sunrise_special/4/GetDisk 2.0.md create mode 100644 sunrise_special/4/HD Indelen.md create mode 100644 sunrise_special/4/HEX Printen.md create mode 100644 sunrise_special/4/Index registers.md create mode 100644 sunrise_special/4/Kun-Basic Cursus.md create mode 100644 sunrise_special/4/MBScan.md create mode 100644 sunrise_special/4/MSX Audio.md create mode 100644 sunrise_special/4/NTM Coordin.md create mode 100644 sunrise_special/4/PCM Rechtstreeks.md create mode 100644 sunrise_special/4/Print routine.md create mode 100644 sunrise_special/4/R800 Drive.md create mode 100644 sunrise_special/4/Random.md create mode 100644 sunrise_special/4/Read to kana.md create mode 100644 sunrise_special/4/Tweede drive aan turbo r.md create mode 100644 sunrise_special/4/V9990 Specificaties.md create mode 100644 sunrise_special/4/V9990.md create mode 100644 sunrise_special/4/VDP Cursus 5.md create mode 100644 sunrise_special/4/VDP Curus 6.md create mode 100644 sunrise_special/4/Werken met ASCII C deel 2.md create mode 100644 sunrise_special/5/C Cursus deel 6.md create mode 100644 sunrise_special/5/Fout vertaler.md create mode 100644 sunrise_special/5/Frequenty analyzer.md create mode 100644 sunrise_special/5/Gestruktureerd programmeren.md create mode 100644 sunrise_special/5/HD op write protected.md create mode 100644 sunrise_special/5/IO Interface.md create mode 100644 sunrise_special/5/Interrupt mode 2.md create mode 100644 sunrise_special/5/MIDI een taal in beweging.md create mode 100644 sunrise_special/5/Make and change directory.md create mode 100644 sunrise_special/5/Memman Bugje.md create mode 100644 sunrise_special/5/Picture packer.md create mode 100644 sunrise_special/5/R800 rom ram lezen.md create mode 100644 sunrise_special/5/Rekenen op Z80.md create mode 100644 sunrise_special/5/Shem.md create mode 100644 sunrise_special/5/Software projecten deel 1.md create mode 100644 sunrise_special/5/Spelontwerp 2.md create mode 100644 sunrise_special/5/Sprites in ML deel 2.md create mode 100644 sunrise_special/5/To.md create mode 100644 sunrise_special/5/Turbo Loader.md create mode 100644 sunrise_special/5/Uncall.md create mode 100644 sunrise_special/5/VDP Cursus 7.md create mode 100644 sunrise_special/5/VDP Cursus 8.md create mode 100644 sunrise_special/5/VDP Cursus 9.md create mode 100644 sunrise_special/5/Werken met ASCII C deel 3.md create mode 100644 sunrise_special/5/Z80dis.md create mode 100644 sunrise_special/6/Bepalen van nulpunten.md create mode 100644 sunrise_special/6/Clock en batterij memory.md create mode 100644 sunrise_special/6/Cursus modula deel 1.md create mode 100644 sunrise_special/6/Een muis met een staartje.md create mode 100644 sunrise_special/6/Files voor MSX View.md create mode 100644 sunrise_special/6/Gestruktureerd programmeren in ML deel 2.md create mode 100644 sunrise_special/6/HDSpeed.md create mode 100644 sunrise_special/6/Luna.md create mode 100644 sunrise_special/6/MSX View.md create mode 100644 sunrise_special/6/MSX2 Blink besturing.md create mode 100644 sunrise_special/6/Memman TSR Development Kit.md create mode 100644 sunrise_special/6/Memman in theorie en praktijk.md create mode 100644 sunrise_special/6/Memory Mapper.md create mode 100644 sunrise_special/6/Modula2.md create mode 100644 sunrise_special/6/SCC geluid via stereo pak.md create mode 100644 sunrise_special/6/Sprites in de praktijk.md create mode 100644 sunrise_special/6/Subdirs onder DOS1.md create mode 100644 sunrise_special/6/Turbo Modula-2.md create mode 100644 sunrise_special/6/Valburg systeem.md create mode 100644 sunrise_special/6/Waarom Modula2.md create mode 100644 sunrise_special/7/Barcode.md create mode 100644 sunrise_special/7/CMD Mode V9958.md create mode 100644 sunrise_special/7/Diskette elende.md create mode 100644 sunrise_special/7/Erix Driver.md create mode 100644 sunrise_special/7/Gestructureerd ML deel 3.md create mode 100644 sunrise_special/7/Harddisks op MSX.md create mode 100644 sunrise_special/7/Interfacing RS232.md create mode 100644 sunrise_special/7/Luna.md create mode 100644 sunrise_special/7/ML Technieken.md create mode 100644 sunrise_special/7/Midi Cursus.md create mode 100644 sunrise_special/7/Music Module naar 256k.md create mode 100644 sunrise_special/7/Nogmaals BDOS routines.md create mode 100644 sunrise_special/7/Score in ML.md create mode 100644 sunrise_special/7/Toetsenborden en microbiologie.md create mode 100644 sunrise_special/7/VDP Cursus 11.md create mode 100644 sunrise_special/7/VDP Cursus 12.md create mode 100644 sunrise_special/7/VDP Cursus 13.md create mode 100644 sunrise_special/7/VDP Cursus 14.md create mode 100644 sunrise_special/7/VDP Cursus 15.md create mode 100644 sunrise_special/7/VDP Cursus 16.md create mode 100644 sunrise_special/7/Valburg reactie.md diff --git a/README.md b/README.md index 8fb2975..41ad6c0 100644 --- a/README.md +++ b/README.md @@ -7,190 +7,190 @@ Happy reading!! | Title | Author | Disk Magazine | | --- | --- | --- | -| [Assembly cursus 2](Future Disk/33/Assembly cursus 2.md) | Arjan Bakker | Future Disk 33 | -| [Assembly cursus 3](Future Disk/34/Assembly cursus 3.md) | Arjan Bakker | Future Disk 34 | -| [Assembly cursus 4](Future Disk/35/Assembly cursus 4.md) | Arjan Bakker | Future Disk 35 | -| [Assembly cursus 5](Future Disk/36/Assembly cursus 5.md) | Arjan Bakker | Future Disk 36 | -| [Assembly cursus 6](Future Disk/37/Assembly cursus 6.md) | Arjan Bakker | Future Disk 37 | -| [Assembly cursus 7](Future Disk/38/Assembly cursus 7.md) | Arjan Bakker | Future Disk 38 | -| [Assembly cursus 8](Future Disk/40/Assembly cursus 8.md) | Arjan Bakker | Future Disk 40 | -| [Assembly cursus 9](Future Disk/42/Assembly cursus 9.md) | Arjan Bakker | Future Disk 42 | -| [Assembly voor beginners](Future Disk/30/Assembly voor beginners.md) | Arjan Bakker | Future Disk 30 | -| [Bits en bull](Future Disk/33/Bits en bull.md) | Tobias Keizer | Future Disk 33 | -| [CDD](Sunrise Special/2/CDD.md) | Stefan Boer | Sunrise Special 2 | -| [Cirkels in ML](Future Disk/02/Cirkels in ML.md) | Jeroen Smael | Future Disk 02 | -| [Data compressie](Future Disk/15/Data compressie.md) | Jan-Willem van Helden | Future Disk 15 | -| [Data compressie 2](Future Disk/17/Data compressie 2.md) | Jan-Willem van Helden | Future Disk 17 | -| [Data compressie 3](Future Disk/18/Data compressie 3.md) | Jan-Willem van Helden | Future Disk 18 | -| [Data compressie 4](Future Disk/20/Data compressie 4.md) | Jan-Willem van Helden | Future Disk 20 | -| [Data compressie 5](Future Disk/22/Data compressie 5.md) | Jan-Willem van Helden | Future Disk 22 | -| [Data compressie](Future Disk/35/Datacompressie.md) | Arjan Bakker | Future Disk 35 | -| [Data compressie 2](Future Disk/36/Datacompressie 2.md) | Arjan Bakker | Future Disk 36 | -| [Disk cursus special 1](Sunrise Special/1/Disk cursus special 1.md) | Stefan Boer | Sunrise Special 1 | -| [File handles](Sunrise Special/3/File handles.md) | Kasper Souren | Sunrise Special 3 | -| [Geheugen schakelen](Sunrise Special/2/Geheugen schakelen.md) | Stefan Boer | Sunrise Special 2 | -| [Geheugen tellen](Sunrise Special/1/Geheugen tellen.md) | Stefan Boer | Sunrise Special 1 | -| [Getallen printen](Sunrise Special/3/Getallen printen.md) | Stefan Boer | Sunrise Special 3 | -| [Het rel file formaat](Sunrise Special/1/Het rel formaat.md) | Stefan Boer | Sunrise Special 1 | -| [Interrupt service routines](Sunrise Special/2/Interrupt service routines.md) | Alex van der Wal | Sunrise Special 2 | -| [Ledjes](Sunrise Special/2/Ledjes.md) | Stefan Boer | Sunrise Special 2 | -| [Lijntjes](Future Disk/42/Lijntjes.md) | Arjan Bakker | Future Disk 42 | -| [Machinetaal](Future Disk/00/Machinetaal.md) | Ruud Gelissen & Jan-Willem van Helden | Future Disk 0 | -| [Machinetaal 2](Future Disk/00/Machinetaal 2.md) | Ruud Gelissen & Jan-Willem van Helden | Future Disk 1 | -| [Machinetaal 3](Future Disk/02/Machinetaal 3.md) | Ruud Gelissen & Jan-Willem van Helden | Future Disk 2 | -| [Machinetaal 4](Future Disk/03/Machinetaal 4.md) | Ruud Gelissen & Jan-Willem van Helden | Future Disk 3 | -| [Machinetaal 5](Future Disk/04/Machinetaal 5.md) | Ruud Gelissen & Jan-Willem van Helden | Future Disk 4 | -| [Machinetaal 6](Future Disk/05/Machinetaal 6.md) | Ruud Gelissen & Jan-Willem van Helden | Future Disk 5 | -| [Machinetaal 7](Future Disk/06/Machinetaal 7.md) | Ruud Gelissen & Jan-Willem van Helden | Future Disk 6 | -| [Machinetaal 8](Future Disk/07/Machinetaal 8.md) | Ruud Gelissen & Jan-Willem van Helden | Future Disk 7 | -| [Machinetaal 9](Future Disk/075/Machinetaal 9.md) | Ruud Gelissen & Jan-Willem van Helden | Future Disk 7 1/2 | -| [Machinetaal 10](Future Disk/10/Machinetaal 10.md) | Ruud Gelissen & Jan-Willem van Helden | Future Disk 10 | -| [Machinetaal 11](Future Disk/11/Machinetaal 11.md) | Ruud Gelissen & Jan-Willem van Helden | Future Disk 11 | -| [Machinetaal 12](Future Disk/13/Machinetaal 12.md) | Ruud Gelissen & Jan-Willem van Helden | Future Disk 13 | -| [Macro commando's met gen80](Sunrise Special/2/Macro commandos met gen80.md) | Kasper Souren | Sunrise Special 2 | -| [Mathpack](Future Disk/34/Mathpack.md) | Arjan Bakker | Future Disk 34 | -| [Mathpack 2](Future Disk/36/Mathpack 2.md) | Arjan Bakker | Future Disk 36 | -| [Mathpack 3](Future Disk/37/Mathpack 3.md) | Arjan Bakker | Future Disk 37 | -| [Mcode Special 1](Future Disk/19/Mcode Special 1.md) | Ruud Gelissen | Future Disk 19 | -| [Mcode Special 2](Future Disk/21/Mcode Special 2.md) | Ruud Gelissen | Future Disk 21 | -| [Mcode Special 3](Future Disk/23/Mcode Special 3.md) | Ruud Gelissen | Future Disk 23 | -| [Mcode Special 4](Future Disk/25/Mcode Special 4.md) | Ruud Gelissen | Future Disk 25 | -| [Mcode Special 5](Future Disk/27/Mcode Special 5.md) | Ruud Gelissen | Future Disk 27 | -| [MSX Assemblers](Sunrise Special/1/MSX Assemblers.md) | Alex van der Wal | Sunrise Special 1 | -| [MSX-DOS 2 voor machinetaalprogrammeur](Sunrise Special/2/MSX-DOS 2 voor machinetaalprogrammeurs.md) | Daniel Wiermans | Sunrise Special 2 | -| [MSX-DOS2 deel 1](Future Disk/25/MSX-DOS2 deel 1.md) | Tobias Keizer | Future Disk 25 | -| [MSX-DOS2 deel 2](Future Disk/28/MSX-DOS2 deel 2.md) | Tobias Keizer | Future Disk 28 | -| [MSX-DOS2 deel 3](Future Disk/28/MSX-DOS2 deel 3.md) | Tobias Keizer | Future Disk 28 | -| [Muis uitlezen](Sunrise Special/1/Muis uitlezen.md) | Alex van der Wal | Sunrise Special 1 | -| [Paint in ML](Future Disk/30/Paint in ML.md) | Arjan Bakker | Future Disk 30 | -| [Pauze toets](Sunrise Special/2/Pauze toets.md) | Stefan Boer | Sunrise Special 2 | -| [PCM routines van de bios](Sunrise Special/2/PCM routines van de bios.md) | Bernard Lamers | Sunrise Special 2 | -| [PCM Sampler](Sunrise Special/2/PCM Sampler.md) | Stefan Boer | Sunrise Special 2 | -| [R800](Sunrise Special/1/R800.md) | Stefan Boer | Sunrise Special 1 | -| [Rechtstreeks via PCM afspelen](Sunrise Special/2/Rechtstreeks via PCM afspelen.md) | Pierre Gielen | Sunrise Special 2 | -| [Rel assembleren](Sunrise Special/1/Rel assembleren.md) | Rudy Oppers | Sunrise Special 1 | -| [Resource dis-assembler](Sunrise Special/2/Resource.md) | Kasper Souren | Sunrise Special 2 | -| [ROM images laden](Future Disk/36/ROM images laden.md) | Arjan Bakker | Future Disk 36 | -| [Rotatie](Future Disk/27/Rotatie.md) | Jan-Willem van Helden | Future Disk 27 | -| [Schuiven en roteren](FD40/Schuiven en roteren.md) | Arjan | Future Disk 40 | -| [Screen 12](Future Disk/21/Screen 12.md) | Tobias Keizer | Future Disk 21 | -| [Screen 4](Future Disk/32/Screen 4.md) | Jan-Willem van Helden | Future Disk 32 | -| [The PCM sample processor](Future Disk/28/The PCM sample processor.md) | Tobias Keizer | Future Disk 28 | -| [Undocumented Z80 code.md](Future Disk/18/Undocumented Z80 code.md) | Digital JW | Future Disk 18 | -| [V9958 in ML.md](Future Disk/24/V9958 in ML.md) | Tobias Keizer | Future Disk 24 | -| [VDP Commando Registers](Sunrise Special/3/VDP Commando Registers.md) | Stefan Boer | Sunrise Special 2 | -| [VDP Cursus 1](Sunrise Special/2/VDP Cursus 1.md) | Stefan Boer | Sunrise Special 2 | -| [VDP Cursus 2](Sunrise Special/2/VDP Cursus 2.md) | Stefan Boer | Sunrise Special 2 | -| [VDP Cursus 3](Sunrise Special/3/VDP Cursus 3.md) | Stefan Boer | Sunrise Special 3 | -| [VDP Cursus 4](Sunrise Special/3/VDP Cursus 4.md) | Stefan Boer | Sunrise Special 3 | +| [Assembly cursus 2](future_disk/33/assembly_cursus_2.md) | Arjan Bakker | Future Disk 33 | +| [Assembly cursus 3](future_disk/34/assembly_cursus_3.md) | Arjan Bakker | Future Disk 34 | +| [Assembly cursus 4](future_disk/35/assembly_cursus_4.md) | Arjan Bakker | Future Disk 35 | +| [Assembly cursus 5](future_disk/36/assembly_cursus_5.md) | Arjan Bakker | Future Disk 36 | +| [Assembly cursus 6](future_disk/37/assembly_cursus_6.md) | Arjan Bakker | Future Disk 37 | +| [Assembly cursus 7](future_disk/38/assembly_cursus_7.md) | Arjan Bakker | Future Disk 38 | +| [Assembly cursus 8](future_disk/40/assembly_cursus_8.md) | Arjan Bakker | Future Disk 40 | +| [Assembly cursus 9](future_disk/42/assembly_cursus_9.md) | Arjan Bakker | Future Disk 42 | +| [Assembly voor beginners](future_disk/30/assembly_voor_beginners.md) | Arjan Bakker | Future Disk 30 | +| [Bits en bull](future_disk/33/bits_en_bull.md) | Tobias Keizer | Future Disk 33 | +| [CDD](sunrise_special/2/cdd.md) | Stefan Boer | Sunrise Special 2 | +| [Cirkels in ML](future_disk/02/cirkels_in_ml.md) | Jeroen Smael | Future Disk 02 | +| [Data compressie](future_disk/15/data_compressie.md) | Jan-Willem van Helden | Future Disk 15 | +| [Data compressie 2](future_disk/17/data_compressie_2.md) | Jan-Willem van Helden | Future Disk 17 | +| [Data compressie 3](future_disk/18/data_compressie_3.md) | Jan-Willem van Helden | Future Disk 18 | +| [Data compressie 4](future_disk/20/data_compressie_4.md) | Jan-Willem van Helden | Future Disk 20 | +| [Data compressie 5](future_disk/22/data_compressie_5.md) | Jan-Willem van Helden | Future Disk 22 | +| [Data compressie](future_disk/35/datacompressie.md) | Arjan Bakker | Future Disk 35 | +| [Data compressie 2](future_disk/36/datacompressie_2.md) | Arjan Bakker | Future Disk 36 | +| [Disk cursus special 1](sunrise_special/1/disk_cursus_special_1.md) | Stefan Boer | Sunrise Special 1 | +| [File handles](sunrise_special/3/file_handles.md) | Kasper Souren | Sunrise Special 3 | +| [Geheugen schakelen](sunrise_special/2/geheugen_schakelen.md) | Stefan Boer | Sunrise Special 2 | +| [Geheugen tellen](sunrise_special/1/geheugen_tellen.md) | Stefan Boer | Sunrise Special 1 | +| [Getallen printen](sunrise_special/3/getallen_printen.md) | Stefan Boer | Sunrise Special 3 | +| [Het rel file formaat](sunrise_special/1/het_rel_formaat.md) | Stefan Boer | Sunrise Special 1 | +| [Interrupt service routines](sunrise_special/2/interrupt_service_routines.md) | Alex van der Wal | Sunrise Special 2 | +| [Ledjes](sunrise_special/2/ledjes.md) | Stefan Boer | Sunrise Special 2 | +| [Lijntjes](future_disk/42/lijntjes.md) | Arjan Bakker | Future Disk 42 | +| [Machinetaal](future_disk/00/machinetaal.md) | Ruud Gelissen & Jan-Willem van Helden | Future Disk 0 | +| [Machinetaal 2](future_disk/00/machinetaal_2.md) | Ruud Gelissen & Jan-Willem van Helden | Future Disk 1 | +| [Machinetaal 3](future_disk/02/Machinetaal_3.md) | Ruud Gelissen & Jan-Willem van Helden | Future Disk 2 | +| [Machinetaal 4](future_disk/03/machinetaal_4.md) | Ruud Gelissen & Jan-Willem van Helden | Future Disk 3 | +| [Machinetaal 5](future_disk/04/machinetaal_5.md) | Ruud Gelissen & Jan-Willem van Helden | Future Disk 4 | +| [Machinetaal 6](future_disk/05/machinetaal_6.md) | Ruud Gelissen & Jan-Willem van Helden | Future Disk 5 | +| [Machinetaal 7](future_disk/06/machinetaal_7.md) | Ruud Gelissen & Jan-Willem van Helden | Future Disk 6 | +| [Machinetaal 8](future_disk/07/machinetaal_8.md) | Ruud Gelissen & Jan-Willem van Helden | Future Disk 7 | +| [Machinetaal 9](future_disk/075/machinetaal_9.md) | Ruud Gelissen & Jan-Willem van Helden | Future Disk 7 1/2 | +| [Machinetaal 10](future_disk/10/machinetaal_10.md) | Ruud Gelissen & Jan-Willem van Helden | Future Disk 10 | +| [Machinetaal 11](future_disk/11/machinetaal_11.md) | Ruud Gelissen & Jan-Willem van Helden | Future Disk 11 | +| [Machinetaal 12](future_disk/13/machinetaal_12.md) | Ruud Gelissen & Jan-Willem van Helden | Future Disk 13 | +| [Macro commando's met gen80](sunrise_special/2/macro_commandos_met_gen80.md) | Kasper Souren | Sunrise Special 2 | +| [Mathpack](future_disk/34/mathpack.md) | Arjan Bakker | Future Disk 34 | +| [Mathpack 2](future_disk/36/mathpack_2.md) | Arjan Bakker | Future Disk 36 | +| [Mathpack 3](future_disk/37/mathpack_3.md) | Arjan Bakker | Future Disk 37 | +| [Mcode Special 1](future_disk/19/mcode_special_1.md) | Ruud Gelissen | Future Disk 19 | +| [Mcode Special 2](future_disk/21/mcode_special_2.md) | Ruud Gelissen | Future Disk 21 | +| [Mcode Special 3](future_disk/23/mcode_special_3.md) | Ruud Gelissen | Future Disk 23 | +| [Mcode Special 4](future_disk/25/mcode_special_4.md) | Ruud Gelissen | Future Disk 25 | +| [Mcode Special 5](future_disk/27/mcodespecial_5.md) | Ruud Gelissen | Future Disk 27 | +| [MSX Assemblers](sunrise_special/1/msx_assemblers.md) | Alex van der Wal | Sunrise Special 1 | +| [MSX-DOS 2 voor machinetaalprogrammeur](sunrise_special/2/msx-dos_2_voor_machinetaalprogrammeurs.md) | Daniel Wiermans | Sunrise Special 2 | +| [MSX-DOS2 deel 1](future_disk/25/msx-dos2_deel_1.md) | Tobias Keizer | Future Disk 25 | +| [MSX-DOS2 deel 2](future_disk/28/msx-dos2_deel_2.md) | Tobias Keizer | Future Disk 28 | +| [MSX-DOS2 deel 3](future_disk/28/msx-dos2_deel_3.md) | Tobias Keizer | Future Disk 28 | +| [Muis uitlezen](sunrise_special/1/muis_uitlezen.md) | Alex van der Wal | Sunrise Special 1 | +| [Paint in ML](future_disk/30/paint_in_ml.md) | Arjan Bakker | Future Disk 30 | +| [Pauze toets](sunrise_special/2/pauze_toets.md) | Stefan Boer | Sunrise Special 2 | +| [PCM routines van de bios](sunrise_special/2/pcm_routines_van_de_bios.md) | Bernard Lamers | Sunrise Special 2 | +| [PCM Sampler](sunrise_special/2/pcm_sampler.md) | Stefan Boer | Sunrise Special 2 | +| [R800](sunrise_special/1/r800.md) | Stefan Boer | Sunrise Special 1 | +| [Rechtstreeks via PCM afspelen](sunrise_special/2/rechtstreeks_via_pcm_afspelen.md) | Pierre Gielen | Sunrise Special 2 | +| [Rel assembleren](sunrise_special/1/rel_assembleren.md) | Rudy Oppers | Sunrise Special 1 | +| [Resource dis-assembler](sunrise_special/2/resource.md) | Kasper Souren | Sunrise Special 2 | +| [ROM images laden](future_disk/36/rom_images_laden.md) | Arjan Bakker | Future Disk 36 | +| [Rotatie](future_disk/27/rotatie.md) | Jan-Willem van Helden | Future Disk 27 | +| [Schuiven en roteren](FD40/schuiven_en_roteren.md) | Arjan | Future Disk 40 | +| [Screen 12](future_disk/21/screen_12.md) | Tobias Keizer | Future Disk 21 | +| [Screen 4](future_disk/32/screen_4.md) | Jan-Willem van Helden | Future Disk 32 | +| [The PCM sample processor](future_disk/28/the_pcm_sample_processor.md) | Tobias Keizer | Future Disk 28 | +| [Undocumented Z80 code.md](future_disk/18/undocumented_z80_code.md) | Digital JW | Future Disk 18 | +| [V9958 in ML.md](future_disk/24/v9958_in_ml.md) | Tobias Keizer | Future Disk 24 | +| [VDP Commando Registers](sunrise_special/3/vdp_commando_registers.md) | Stefan Boer | Sunrise Special 2 | +| [VDP Cursus 1](sunrise_special/2/vdp_cursus_1.md) | Stefan Boer | Sunrise Special 2 | +| [VDP Cursus 2](sunrise_special/2/vdp_cursus_2.md) | Stefan Boer | Sunrise Special 2 | +| [VDP Cursus 3](sunrise_special/3/vdp_cursus_3.md) | Stefan Boer | Sunrise Special 3 | +| [VDP Cursus 4](sunrise_special/3/vdp_cursus_4.md) | Stefan Boer | Sunrise Special 3 | ## Basic | Title | Author | Disk Magazine | | --- | --- | --- | -| [2+ Schermen](Future Disk/24/2+ Schermen.md) | Tobias Keizer | Future Disk 24 | -| [Advanced Basic](Future Disk/30/Advances Basic.md) | Arjan Bakker | Future Disk 30 | -| [Advanced Basic 2](Future Disk/31/Advanced Basic 2.md) | Arjan Bakker | Future Disk 31 | -| [Advanced Basic 3](Future Disk/33/Advanced Basic 3.md) | Arjan Bakker | Future Disk 33 | -| [Advanced Basic 4](Future Disk/33/Advanced Basic 4.md) | Arjan Bakker | Future Disk 34 | -| [Advanced Basic 5](Future Disk/36/Advanced Basic 5.md) | Arjan Bakker | Future Disk 36 | -| [Advanced Basic 6](Future Disk/37/Advanced Basic 6.md) | Arjan Bakker | Future Disk 37 | -| [Basic Cursus 6](Future Disk/17/Basic Cursus 6.md) | Tobias Keizer | Future Disk 17 | -| [Basic Cursus 8](Future Disk/19/Basic Cursus 8.md) | Tobias Keizer | Future Disk 19 | -| [Basic voor beginners](Future Disk/19/Basic voor beginners.md) | Tobias Keizer | Future Disk 19 | -| [Call Kanji](Future Disk/21/Call Kanji.md) | Tobias Keizer | Future Disk 21 | -| [Copy in BASIC](Future Disk/25/Copy in BASIC.md) | Vincent | Future Disk 35 | -| [DIsk IO in BASIC](Future Disk/31/Disk IO in BASIC.md) | Tobias Keizer | Future Disk 31 | -| [Ledjes](Future Disk/21/Ledjes.md) | Tobias Keizer | Future Disk 21 | -| [MSX2+ Schermen in BASIC](Future Disk/19/MSX2+ Schermen in BASIC.md) | Tobias Keizer | Future Disk 19 | -| [Muizen in BASIC](Future Disk/20/Muizen in BASIC.md) | Tobias Keizer | Future Disk 20 | -| [Set scroll in basic](Sunrise Special/1/Set scroll in basic.md) | Rudy Oppers | Sunrise Special 1 | -| [Special Effects BASIC](Future Disk/05/Special Effects BASIC.md) | Tom Wauben | Future Disk 5 | -| [Special Effects BASIC 2](Future Disk/06/Special Effects BASIC 2.md) | Tom Wauben | Future Disk 6 | -| [Special Effects BASIC 3](Future Disk/07/Special Effects BASIC 3.md) | Tom Wauben | Future Disk 7 | -| [Special Effects BASIC 4](Future Disk/075/Special Effects BASIC 4.md) | Tom Wauben | Future Disk 7 1/2 | -| [Special Effects BASIC 5](Future Disk/10/Special Effects BASIC 5.md) | Tom Wauben | Future Disk 10 | -| [Special Effects BASIC 5](Future Disk/12/Special Effects BASIC 5.md) | Tom Wauben | Future Disk 12 | -| [Turbo-R BASIC](Future Disk/750/Turbo-R BASIC.md) | Tobias Keizer | Future Disk 7 1/2 | -| [Turbo-R BASIC](Future Disk/20/Turbo-R BASIC.md) | Tobias Keizer | Future Disk 20 | +| [2+ Schermen](future_disk/24/2+_schermen.md) | Tobias Keizer | Future Disk 24 | +| [Advanced Basic](future_disk/30/advances_basic.md) | Arjan Bakker | Future Disk 30 | +| [Advanced Basic 2](future_disk/31/advanced_basic_2.md) | Arjan Bakker | Future Disk 31 | +| [Advanced Basic 3](future_disk/33/advanced_basic_3.md) | Arjan Bakker | Future Disk 33 | +| [Advanced Basic 4](future_disk/33/advanced_basic_4.md) | Arjan Bakker | Future Disk 34 | +| [Advanced Basic 5](future_disk/36/advanced_basic_5.md) | Arjan Bakker | Future Disk 36 | +| [Advanced Basic 6](future_disk/37/advanced_basic_6.md) | Arjan Bakker | Future Disk 37 | +| [Basic Cursus 6](future_disk/17/basic_cursus_6.md) | Tobias Keizer | Future Disk 17 | +| [Basic Cursus 8](future_disk/19/basic_cursus_8.md) | Tobias Keizer | Future Disk 19 | +| [Basic voor beginners](future_disk/19/basic_voor_beginners.md) | Tobias Keizer | Future Disk 19 | +| [Call Kanji](future_disk/21/call_kanji.md) | Tobias Keizer | Future Disk 21 | +| [Copy in BASIC](future_disk/25/copy_in_basic.md) | Vincent | Future Disk 35 | +| [DIsk IO in BASIC](future_disk/31/disk_io_in_basic.md) | Tobias Keizer | Future Disk 31 | +| [Ledjes](future_disk/21/ledjes.md) | Tobias Keizer | Future Disk 21 | +| [MSX2+ Schermen in BASIC](future_disk/19/msx2+_schermen_in_basic.md) | Tobias Keizer | Future Disk 19 | +| [Muizen in BASIC](future_disk/20/muizen_in_basic.md) | Tobias Keizer | Future Disk 20 | +| [Set scroll in basic](sunrise_special/1/set_scroll_in_basic.md) | Rudy Oppers | Sunrise Special 1 | +| [Special Effects BASIC](future_disk/05/special_effects_BASIC.md) | Tom Wauben | Future Disk 5 | +| [Special Effects BASIC 2](future_disk/06/special_effects_basic_2.md) | Tom Wauben | Future Disk 6 | +| [Special Effects BASIC 3](future_disk/07/special_effects_basic_3.md) | Tom Wauben | Future Disk 7 | +| [Special Effects BASIC 4](future_disk/075/special_effects_basic_4.md) | Tom Wauben | Future Disk 7 1/2 | +| [Special Effects BASIC 5](future_disk/10/special_effects_basic_5.md) | Tom Wauben | Future Disk 10 | +| [Special Effects BASIC 5](future_disk/12/special_effects_basic_5.md) | Tom Wauben | Future Disk 12 | +| [Turbo-R BASIC](future_disk/750/turbo-r_basic.md) | Tobias Keizer | Future Disk 7 1/2 | +| [Turbo-R BASIC](future_disk/20/turbo-r_basic.md) | Tobias Keizer | Future Disk 20 | ## C | Title | Author | Disk Magazine | | --- | --- | --- | -| [Programmeer taal c](Sunrise Special/2/Programmeer taal c.md) | Robert Amesz | Sunrise Special 2 | -| [Programmeer taal c 2](Sunrise Special/2/Programmeer taal c 2.md) | Robert Amesz | Sunrise Special 2 | -| [Programmeer taal c 3](Sunrise Special/3/De programmeer taal C deel 3.md) | Robert Amesz | Sunrise Special 3 | -| [Programmeer taal c 4](Sunrise Special/3/De programmeer taal C deel 4.md) | Robert Amesz | Sunrise Special 3 | -| [Werken met ASCII C.md](Sunrise Special/3/Werken met ASCII C.md) | Alex Wulms | Sunrise Special 3 | +| [Programmeer taal c](sunrise_special/2/programmeer_taal_c.md) | Robert Amesz | Sunrise Special 2 | +| [Programmeer taal c 2](sunrise_special/2/programmeer_taal_c_2.md) | Robert Amesz | Sunrise Special 2 | +| [Programmeer taal c 3](sunrise_special/3/de_programmeer_taal_c_deel_3.md) | Robert Amesz | Sunrise Special 3 | +| [Programmeer taal c 4](sunrise_special/3/de_programmeer_taal_c_deel_4.md) | Robert Amesz | Sunrise Special 3 | +| [Werken met ASCII C.md](sunrise_special/3/werken_met_ascii_c.md) | Alex Wulms | Sunrise Special 3 | ## Hybrid (Basic + Assembly) | Title | Author | Disk Magazine | | --- | --- | --- | -| [Blinkmode](Sunrise Special/2/Blinkmode.md) | Stefan Boer | Sunrise Special 2 | -| [Hybride Call Commando's](Sunrise Special/3/Hybride Call Commando's.md) | Stefan Boer | Sunrise Special 3 | -| [Hybride programmeren](Sunrise Special/1/Hybride programmeren.md) | Stefan Boer | Sunrise Special 1 | -| [Programmeren sample chip](Sunrise Special/3/Programmeren sample chip.md) | Bart Schouten | Sunrise Special 3 | -| [Scrollen in kun basic](Sunrise Special/3/Scrollen in kun basic.md) | Randy Simons | Sunrise Special 3 | -| [Turbo-R systeemcounter](Sunrise Special/3/Turbo-R systeemcounter.md) | Stefan Boer | Sunrise Special 3 | +| [Blinkmode](sunrise_special/2/blinkmode.md) | Stefan Boer | Sunrise Special 2 | +| [Hybride Call Commando's](sunrise_special/3/hybride_call_commandos.md) | Stefan Boer | Sunrise Special 3 | +| [Hybride programmeren](sunrise_special/1/hybride_programmeren.md) | Stefan Boer | Sunrise Special 1 | +| [Programmeren sample chip](sunrise_special/3/programmeren_sample_chip.md) | Bart Schouten | Sunrise Special 3 | +| [Scrollen in kun basic](sunrise_special/3/scrollen_in_kun_basic.md) | Randy Simons | Sunrise Special 3 | +| [Turbo-R systeemcounter](sunrise_special/3/turbo-r_systeemcounter.md) | Stefan Boer | Sunrise Special 3 | ## Memman | Title | Author | Disk Magazine | | --- | --- | --- | -| [Memman 2.3 intro](Sunrise Special/1/Memman 2.3 intro.md) | Ries Vriend/Ramon van der Winkel/Robbert Wethmar | Sunrise Special 1 | -| [Memman 2.3 specificaties](Sunrise Special/1/Memman 2.3 specificaties.md) | Ries Vriend / Ramon van der Winkel - c MST | Sunrise Special 1 | -| [Memman 2.42](Sunrise Special/2/Memman 2.42.md) | Stefan Boer / Kasper Souren | Sunrise Special 2 | -| [Memman problemen](Sunrise Special/3/Memman problemen.md) | Henk Hoogvliet | Sunrise Special 3 | -| [TSR Change CPU](Sunrise Special/3/TSR Change CPU.md) | Kasper Souren | Sunrise Special 3 | -| [TSR Development kit](Sunrise Special/3/TSR Development kit.md) | Kasper Souren | Sunrise Special 3 | -| [TSR Volume Input Meter](Sunrise Special/3/TSR Volume Input Meter.md) | Kasper Souren | Sunrise Special 3 | +| [Memman 2.3 intro](sunrise_special/1/memman_2.3_intro.md) | Ries Vriend/Ramon van der Winkel/Robbert Wethmar | Sunrise Special 1 | +| [Memman 2.3 specificaties](sunrise_special/1/memman_2.3_specificaties.md) | Ries Vriend / Ramon van der Winkel - c MST | Sunrise Special 1 | +| [Memman 2.42](sunrise_special/2/memman_2.42.md) | Stefan Boer / Kasper Souren | Sunrise Special 2 | +| [Memman problemen](sunrise_special/3/memman_problemen.md) | Henk Hoogvliet | Sunrise Special 3 | +| [TSR Change CPU](sunrise_special/3/tsr_change_cpu.md) | Kasper Souren | Sunrise Special 3 | +| [TSR Development kit](sunrise_special/3/tsr_development_kit.md) | Kasper Souren | Sunrise Special 3 | +| [TSR Volume Input Meter](sunrise_special/3/tsr_volume_input_meter.md) | Kasper Souren | Sunrise Special 3 | ## Other | Title | Author | Disk Magazine | | --- | --- | --- | -| [Clock chip](Future Disk/25/Clock chip.md) | ? | Future Disk 25 | -| [Cursus DD-Graph](Sunrise Special/2/Cursus dd-graph.md) | Bart Schouten | Sunrise Special 2 | -| [De archeologie van de MSX](Sunrise Special/3/De archeologie van de MSX.md) | Bart Schouten | Sunrise Special 2 | -| [Get disk](Sunrise Special/3/Getdisk.md) | Michel Shuqair | Sunrise Special 3 | -| [Moonblaster Music Cursus](Future Disk/18/Moonblaster Music Cursus.md) | Jorrith Schaap | Future Disk 18 | -| [Moonblaster Music Cursus 2](Future Disk/19/Moonblaster Music Cursus 2.md) | Jorrith Schaap | Future Disk 19 | -| [Moonblaster Music Cursus 3](Future Disk/20/Moonblaster Music Cursus 3.md) | Jorrith Schaap | Future Disk 20 | -| [Moonblaster Music Cursus 4](Future Disk/21/Moonblaster Music Cursus 4.md) | Jorrith Schaap | Future Disk 21 | -| [Moonblaster Music Cursus 5](Future Disk/22/Moonblaster Music Cursus 5.md) | Jorrith Schaap | Future Disk 22 | -| [MSX-DOS 2.31](Sunrise Special/2/MSX-DOS 2.31.md) | Kasper Souren | Sunrise Special 2 | -| [MSX-DOS 2 - Redirection](Sunrise Special/2/Redirection.md) | Kasper Souren | Sunrise Special 2 | -| [Rescursief programmeren](Sunrise Special/1/Recursief programmeren.md) | Alex van der Wal | Sunrise Special 1 | -| [Stereo SCC](Sunrise Special/2/Stereo SCC.md) | Haiko de Boer | Sunrise Special 2 | -| [Te zachte PSG bij de NMS 8250/55/80](Sunrise Special/1/Te zachte PSG bij de NMS 8250 55 80.md) | Haiko de Boer | Sunrise Special 1 | -| [The 2+ Corner](Future Disk/15/The 2+ Corner.md) | Marcel Otten | Future Disk 15 | -| [Track 0 op de turbo-r](Sunrise Special/1/Track 0 op de turbo-r.md) | Stefan Boer | Sunrise Special 1 | +| [Clock chip](future_disk/25/clock_chip.md) | ? | Future Disk 25 | +| [Cursus DD-Graph](sunrise_special/2/cursus_dd-graph.md) | Bart Schouten | Sunrise Special 2 | +| [De archeologie van de MSX](sunrise_special/3/de_archeologie_van_de_msx.md) | Bart Schouten | Sunrise Special 2 | +| [Get disk](sunrise_special/3/getdisk.md) | Michel Shuqair | Sunrise Special 3 | +| [Moonblaster Music Cursus](future_disk/18/moonblaster_music_cursus.md) | Jorrith Schaap | Future Disk 18 | +| [Moonblaster Music Cursus 2](future_disk/19/moonblaster_music_cursus_2.md) | Jorrith Schaap | Future Disk 19 | +| [Moonblaster Music Cursus 3](future_disk/20/moonblaster_music_cursus_3.md) | Jorrith Schaap | Future Disk 20 | +| [Moonblaster Music Cursus 4](future_disk/21/moonblaster_music_cursus_4.md) | Jorrith Schaap | Future Disk 21 | +| [Moonblaster Music Cursus 5](future_disk/22/moonblaster_music_cursus_5.md) | Jorrith Schaap | Future Disk 22 | +| [MSX-DOS 2.31](sunrise_special/2/msx-dos_2.31.md) | Kasper Souren | Sunrise Special 2 | +| [MSX-DOS 2 - Redirection](sunrise_special/2/redirection.md) | Kasper Souren | Sunrise Special 2 | +| [Rescursief programmeren](sunrise_special/1/recursief_programmeren.md) | Alex van der Wal | Sunrise Special 1 | +| [Stereo SCC](sunrise_special/2/stereo_scc.md) | Haiko de Boer | Sunrise Special 2 | +| [Te zachte PSG bij de NMS 8250/55/80](sunrise_special/1/te_zachte_psg_bij_de_NMS_8250_55_80.md) | Haiko de Boer | Sunrise Special 1 | +| [The 2+ Corner](future_disk/15/the_2+_corner.md) | Marcel Otten | Future Disk 15 | +| [Track 0 op de turbo-r](sunrise_special/1/track_0_op_de_turbo-r.md) | Stefan Boer | Sunrise Special 1 | ## Pascal | Title | Author | Disk Magazine | | --- | --- | --- | -| [Pascal cursus 1](Future Disk/11/Pascal 1.md) | Jeroen Smael | Future Disk 11 | -| [Pascal cursus 2](Future Disk/12/Pascal 2.md) | Jeroen Smael | Future Disk 12 | -| [Pascal cursus 3](Future Disk/13/Pascal 3.md) | Jeroen Smael | Future Disk 13 | -| [Pascal cursus 4](Future Disk/14/Pascal 4.md) | Jeroen Smael | Future Disk 14 | -| [Pascal cursus 5](Future Disk/15/Pascal 5.md) | Jeroen Smael | Future Disk 15 | -| [Pascal cursus 6](Future Disk/17/Pascal 6.md) | Jeroen Smael | Future Disk 17 | -| [Pascal cursus 7](Future Disk/18/Pascal 7.md) | Jeroen Smael | Future Disk 18 | -| [Pascal cursus 8](Future Disk/19/Pascal 8.md) | Jeroen Smael | Future Disk 19 | -| [Pascal cursus 1 (Dutch)](Future Disk/32/Pascal cursus 1 NL.md) | Jeroen Smael | Future Disk 32 | -| [Pascal cursus 1 (English)](Future Disk/32/Pascal cursus 1 EN.md) | Jeroen Smael | Future Disk 32 | -| [Pascal cursus 2 (Dutch)](Future Disk/32/Pascal cursus 2 NL.md) | Jeroen Smael | Future Disk 32 | -| [Pascal cursus 2 (English)](Future Disk/32/Pascal cursus 2 EN.md) | Jeroen Smael | Future Disk 32 | -| [Pascal cursus 3](Future Disk/33/Pascal 3.md) | Jeroen Smael | Future Disk 33 | -| [Pascal cursus 4](Future Disk/33/Pascal 4.md) | Jeroen Smael | Future Disk 33 | -| [Pascal cursus 5](Future Disk/34/Pascal 5.md) | Jeroen Smael | Future Disk 34 | -| [Pascal cursus 7](Future Disk/35/Pascal 7.md) | Jeroen Smael | Future Disk 35 | -| [Pascal cursus 8](Future Disk/35/Pascal 8.md) | Jeroen Smael | Future Disk 35 | -| [Pointers in Pascal](Sunrise Special/1/Pointers in Pascal.md) | Rudy Oppers | Sunrise Special 1 | -| [Recursie](Future Disk/21/Recursie.md) | Jeroen Smael | Future Disk 21 | -| [Recursie 2](Future Disk/36/Recursie 2.md) | Jeroen Smael | Future Disk 36 | -| [Turbo Pascal Patch](Sunrise Special/3/Turbo Pascal Patch.md) | Pierre Gielen | Sunrise Special 3 | +| [Pascal cursus 1](future_disk/11/pascal_1.md) | Jeroen Smael | Future Disk 11 | +| [Pascal cursus 2](future_disk/12/pascal_2.md) | Jeroen Smael | Future Disk 12 | +| [Pascal cursus 3](future_disk/13/pascal_3.md) | Jeroen Smael | Future Disk 13 | +| [Pascal cursus 4](future_disk/14/pascal_4.md) | Jeroen Smael | Future Disk 14 | +| [Pascal cursus 5](future_disk/15/pascal_5.md) | Jeroen Smael | Future Disk 15 | +| [Pascal cursus 6](future_disk/17/pascal_6.md) | Jeroen Smael | Future Disk 17 | +| [Pascal cursus 7](future_disk/18/pascal_7.md) | Jeroen Smael | Future Disk 18 | +| [Pascal cursus 8](future_disk/19/pascal_8.md) | Jeroen Smael | Future Disk 19 | +| [Pascal cursus 1 (Dutch)](future_disk/32/pascal_cursus_1_nl.md) | Jeroen Smael | Future Disk 32 | +| [Pascal cursus 1 (English)](future_disk/32/pascal_cursus_1_en.md) | Jeroen Smael | Future Disk 32 | +| [Pascal cursus 2 (Dutch)](future_disk/32/pascal_cursus_2_nl.md) | Jeroen Smael | Future Disk 32 | +| [Pascal cursus 2 (English)](future_disk/32/pascal_cursus_2_en.md) | Jeroen Smael | Future Disk 32 | +| [Pascal cursus 3](future_disk/33/pascal_3.md) | Jeroen Smael | Future Disk 33 | +| [Pascal cursus 4](future_disk/33/pascal_4.md) | Jeroen Smael | Future Disk 33 | +| [Pascal cursus 5](future_disk/34/pascal_5.md) | Jeroen Smael | Future Disk 34 | +| [Pascal cursus 7](future_disk/35/pascal_7.md) | Jeroen Smael | Future Disk 35 | +| [Pascal cursus 8](future_disk/35/pascal_8.md) | Jeroen Smael | Future Disk 35 | +| [Pointers in Pascal](sunrise_special/1/pointers_in_pascal.md) | Rudy Oppers | Sunrise Special 1 | +| [Recursie](future_disk/21/recursie.md) | Jeroen Smael | Future Disk 21 | +| [Recursie 2](future_disk/36/recursie_2.md) | Jeroen Smael | Future Disk 36 | +| [Turbo Pascal Patch](sunrise_special/3/turbo_pascal_patch.md) | Pierre Gielen | Sunrise Special 3 | diff --git a/Future Disk/00/Machinetaal.md b/future_disk/00/machinetaal.md similarity index 100% rename from Future Disk/00/Machinetaal.md rename to future_disk/00/machinetaal.md diff --git a/Future Disk/01/Machinetaal 2.md b/future_disk/01/machinetaal_2.md similarity index 100% rename from Future Disk/01/Machinetaal 2.md rename to future_disk/01/machinetaal_2.md diff --git a/future_disk/02/cirkels_in_ml.md b/future_disk/02/cirkels_in_ml.md new file mode 100644 index 0000000..9f25fa8 --- /dev/null +++ b/future_disk/02/cirkels_in_ml.md @@ -0,0 +1,173 @@ +Cirkels in ML +------------- + +Cirkel = Zuiver Ronde Kring (Prisma Woordenboek p.61) + + +Vele wiskundige genie�n hebben hun hoofd gebroken (niet +letterlijk natuurlijk) over het fenomeen cirkel. Tegenwoordig +doen we niet meer zo lastig over cirkels. Je neemt gewoon je +rekenketel en berekent een aantal sinussen en cosinussen en +voila, een cirkel. + +Op een computer gaat het net zo. Je neemt basic, initialiseerd +een scherm en typt "CIRCLE (100,100),100,15". En wonderwel, er +wordt een cirkel op het scherm afgebeeld. + +Vraag: HOE DOE IK DIT IN ML. + +Antwoord: + +Om antwoord te geven op de vraag zou ik natuurlijk kunnen zeggen +dat je de computer moet gebruiken om een aantal sinus en cosinus +waardes te berekenen en deze vervolgens af te beelden. Hoe +bereken ik echter sinussen en cosinussen in ML. Natuurlijk +springen de wiskundigen onder ons een meter boven hun stoel uit, +want nu kunnen ze gaan zitten kwijlen over +machtreeksontwikkelingen (ja, zo smaakt het ook). Alle +wiskundigen hoeven nu dus niet meer verder te lezen, want zij +kunnen beginnen en h��l v��l geluk. + +Zo, nu zijn alleen de simpele zieltjes overgebleven (waaronder +ik) en kunnen wij het een stuk gemakkelijker aanpakken. + +Waar was ik gebleven, oh ja, cirkels. Om de simpelere oplossing +uit te leggen ga ik beginnen met te zeggen dat ik eigenlijk geen +hele cirkels ga berekenen. Niet gelijk schrikken, je zult het +verschil niet zien hoor. Met simpeler bedoel ik, dat ik maar +1/8ste deel van een cirkel ga berekenen en door een paar +spiegelingen de rest laat tekenen. Verder ga ik ook niet +oneindig veel punten berekenen (een cirkel bestaat theoretisch +uit oneindig veel punten), want dat is te veel werk. Nee, ik ga +gebruik maken van de maximale resolutie van de computer en +daardoor gaat het een stuk sneller. + +Om te beginnen laat ik een "flowchart" zien van de (overigens +niet zelf verzonnen) oplossing: + + +-------------------+ + | x=0 | + | y=R (straal) | + | A=R (hulp teller) | + +---------+---------+ + | ++------------------+ +| | +| + +| / \ +| / \ Nee +| < A----------------+ +| \ / | +| \ / | +| + | +| | Ja | +| +---------+---------+ | +| | y=y-1 | | +| | A=A+y+y | | +| +---------+---------+ | +| | | +| +-------------------+ +| | +| +---------+---------+ +| | Plaats 8 pixels | +| +---------+---------+ +| | +| +---------+---------+ +| | A=A-x-x-1 | +| | x=x+1 | +| +---------+---------+ +| | +| + +| / \ +| Nee / \ ++---------------< x>y > + \ / + \ / + + + | Ja + +---------+---------+ + | Klaar is Klara | + +-------------------+ + +Als we dit kunnen omzetten in ML dan zijn we klaar. Natuurlijk +wil iedereen weten hoe de oplosing werkt. Ik zal niet de +wiskundige afleiding geven, maar het op zijn "boerenfluitjes" +vertellen. + +We beginnen bovenaan de cirkel. Vervolgens trekken we een +horizontale lijn, en wel zolang tot er een punt buiten de cirkel +valt (dit wordt berekend met Pythagoras). Vervolgens gaan we de +lijn een pixel lager tekenen en begint alles van voor af aan. +Als dat niet simpel is en het werkt ook nog eens. Oh ja, voor de +grapjassen die na drie dagen nog aan het tekenen zijn: Stoppen +als x groter dan y is. Verder moet er rekening mee gehouden +worden dat het middelpunt van de cirkel ook de oorsprong van het +assenstelsel is (dat krijg je met wiskundige beschouwingen). + +En dan nu..... Geen cirkels natuurlijk, dat wil zeggen niet +hier, maar wel op de FUTUREDISK zelf. Er staan 3 files op de +FUTUREDISK die met cirkels te maken hebben. + +(1) Deze tekstfile (als je de FUTUREDISK tekstroutine zit, dan +kun je nu op de P drukken om de tekstfile te laten Printen). + +(2) De GEN file CIRCLE. Deze GEN file kun je in je eigen +programma's opnemen als CALL routine. De gebruiksaanwijzing +staat in de GEN file. + +(3) Een kleine demo met cirkels, die vanuit het software-menu +opgestart kan worden. + + +Nog een paar opmerkingen: + +(a) Nu iedereen weet hoe zij/hij (de dames niet vergeten) +cirkels moet maken in ML verwachten wij (ik in het bijzonder) +van de FUTUREDISK binnen enkele weken stapels diskettes te +ontvangen. Op deze diskettes staan dan uiteraard een heleboel +demo's waar cirkels worden getekend. Wat we ook ontvangen, we +zullen het zeker in een van de volgende nummers plaatsen. + +(b) De routine zoals ze in de GEN file staat is een trage +routine. Dit komt, omdat in de routine op het zogenaamde +klipping (buiten beeld vallen van pixels) gecontroleerd wordt. +Als je deze controle weg laat, dan wordt de routine aanzienlijk +sneller. + +(c) De credits voor het bedenken van deze oplossing gaan naar: + +Roland Waclawek + Kreisgenerator + c't 9/86 p.122 + +George Sutty & Steve Blair + Programmer's guide to the EGA/VGA + Brady Books, Simon & Schuster, New York, 1988 + +J�rgen Petsch + Kopierbahnhof VGA-RAM + c't 4/90 p.292 + +Foley, van Dam, Feiner & Hughes + Computer graphics: Principles and Practice + Addison-Wesley, 1990 + +J�rgen Petsch + Turbo-Circle: Schnelle Kreise in Turbo-Pascal! + c't 10/91 p.172 + + + +Voor vragen en/of opmerkingen bel: + + 043-437778 + + + + Groetjes, + + Jeroen "KUBIE" Smael + + + + C YA @ !!!!! diff --git a/future_disk/02/machinetaal_3.md b/future_disk/02/machinetaal_3.md new file mode 100644 index 0000000..76a6665 --- /dev/null +++ b/future_disk/02/machinetaal_3.md @@ -0,0 +1,227 @@ + + Machinetaal cursus deel III + + Welkom bij alweer het derde deel van deze cursus. + Zoals vorige keer beloofd beginnen we dit keer met de INC en + DEC commandos. + + Eerst een klein programmatje: + + ORG 0A000H + LD A,0 + INC A + LD B,255 + DEC B + RET + + Wat doet dit programaatje nu ? We zullen het even van regel + tot regel nalopen. + + ORG 0A000H + + Dit is een assembler instructie die de assembler zegt waar + in het geheugen het programma moet beginnen. In dit + voorbeeld dus op adres 0A000H + + LD A,0 + + Dit is een laadinstructie die we in de vorige cursussen al + behandeld hebben. Het register A wordt geladen met de inhoud + 0. + + INC A + + Aha, dit is dan eindelijk wat nieuws. + INC wil niets meer zeggen dan verhoog (van het Engelse + INCrease). Oftewel, het register A moet met 1 verhoogd + worden. Nu staat er dus in register A het getal 1. + + LD B,255 + + Laad het register B met 255 (in B staan dus nu alle bits op + 1). + + DEC B + + Ook weer een nieuwe instructie. + DEC is het tegenovergestelde van INC. DEC verlaagt dus de + inhoud van een register (van het Engelse DECrease). Nu staat + dus in register B het getal 254. + + RET + + Een instructie die wil zeggen dat het programma beeindigd is + en dat kan worden teruggekeerd naar het hoofdprogramma. + + De instructies INC en DEC kunnen op vele manieren gebruikt + worden en kent daarom een paar vormen. Deze zullen we effe + noemen: + (het nu volgende verhaal geldt voor zowel INC als DEC, in + het voorbeeld zullen we ons aan INC houden) + + INC m + + Verhoogt de door m te specificeren operand met 1. + + m kan zijn: r,(HL),(IX+d) of (IY+d) + + r staat voor alle achtbits registers, dus A,B,C,D,E,H,L + + (HL) betekent dat de inhoud van het adres waar HL naar + verwijst met 1 verhoogd moet worden. + + (IX+d) en (IY+d) willen zeggen, waar de inhoud van IX plus + de relatieve verplaatsing d met 1 verhoogd moet worden. + + INC ss + + verhoogt het door ss gespecificeerde registerpaar met 1 + + ss kan zijn: HL,DE,BC,IY,IX of SP + + Als je dus een INC op een 16-bits getal geeft, wordt ook + hier de inhoud met 1 verhoogt. + + + In het bovenstaande verhaaltje stonden een paar termen + waarvan je nog niets snapt (zoals (HL) of (IX+d)), maar die + zullen in de volgende cursussen nog wel worden uitgelegd. + + Je ziet INC en DEC zijn niet zo'n moeilijke instructies en + door er een beetje mee te spelen weet je al gauw hoe je ze + moet gebruiken. + + Ook vertelden we in de vorige cursus, dat we de JP en de + CALL zouden behandelen. Aangezien belofte schuld maakt, + + + JP en CALL-groep. + + JP en CALL zijn eigenlijk het beste te vergelijken met GOTO + en GOSUB in BASIC. Een CALL wordt, net zoals een GOSUB in + BASIC, afgesloten met een RETurn. + Uit een JumP kun je, eveneens als bij GOTO in BASIC, niet + met een RETurn of zoiets dergelijks terugkeren. + Het is dus al zoals de namen het zeggen: + een JumP staat voor spring (dus niet meer terug) + een CALL staat voor roep aan (en keer nog ooit eens terug). + + Om het allemaal een beetje te verduidelijken, dan nu een + klein listingkje. + + ORG 0A000H + + ST: + LD B,0 + CALL HEGEGA + RET + + HEGEGA: + INC B + RET + + Wat doet dit programma nu: + + ORG 0A000H + + zie boven. + + ST: + + Dit is een label (zie vorige cursus) + + LD B,0 + + Laad het register B met 0 + + CALL HEGEGA + + Roep de subroutine HEGEGA aan. + + RET + + Keer terug naar hoofdprogramma (bv BASIC) + + HEGEGA: + + Label subroutine. + + INC B + + Verhoog register B met 1. + + RET + + Keer terug naar hoofdprogramma (in dit geval dus naar de + instructie na de CALL). + + Dit programmaatje heeft dus niet meer gedaan dan B met 1 + verhoogd (Lees nog maar eens na dankzij onze nieuwe + textroutine, ook KUBIE is eens zo begonnen). + We zullen maar niet uitgaan leggen wat er hardware-matig + gebeurt als er een CALL of een JumP wordt uitgevoerd, want + dat zou helemaal onbegrijpelijk worden. + + In de volgende cursus zullen we een beetje meer MSX gerichte + machinetaal gaan behandelen, want het wordt nu toch wel heel + saai. + + Veel Succes namens: + + Ruud Gelissen en + Jan-Willem van Helden. + + --------Boekenlijst--------- + ZAKBOEKJE Z-80 + + J.B. Vonk -- Kluwer technische boeken -- (c) 1985 + + MACHINETAAL Z-80 + J.B. Vonk/E.J.J. Doppenberg -- Kluwer Tech. Boeken -- + (c) 1987 + + --------Woordenlijst-------- + + ADRES/GEHEUGENADRES/GEHEUGENPLAATS: + + Een plaats in het geheugen van de MSX. + + ASSEMBLER: + + Een programma dat het assembleren uitvoert. + + ASSEMBLEREN: + + Het omzetten van machinetaal naar MCODE. + Voorbeelden van machinetaal zijn de listingen in deze + cursus. + + BIT: + + Een waarde die 0 of 1 kan zijn. + (zie vorige cursussen) + + BYTE: + + Een groepje van 8-BITS. + (zie vorige cursussen) + + LABEL: + + Een naam voor een geheugenplaats, vergelijkbaar + met een regelnummer in BASIC. + + MCODE: + + Dit is de taal waarin de machinetaal commando's worden + omgezet en die de computer kan begrijpen en uitvoeren. + (zie vorige cursussen) + + REGISTER: + + Een register is te vergelijken met een variable + in BASIC. + (zie vorige cursussen) + + Voor vragen zie de Helplines. + diff --git a/future_disk/03/machinetaal_4.md b/future_disk/03/machinetaal_4.md new file mode 100644 index 0000000..2183774 --- /dev/null +++ b/future_disk/03/machinetaal_4.md @@ -0,0 +1,221 @@ +Welkom bij alweer de vierde aflevering van de + machinetaalcursus. + + Nadat we de vorige keren Z80 machinetaal behandelden + zullen we nu eens echt met MSX machinetaal beginnen. + + De eerste MSXjes hadden meestal 32 KROM en 16 KRAM tot + hun beschikking, in de latere modellen werd dit steeds meer. + De Z80 kan eigenlijk niet meer dan 64K tegelijk besturen. + Ho, zegt de Memorymapper bezitter : Wat moet ik dan met mijn + overige Krammetjes. Wel, luidt het antwoord, de Z80 kan niet + meer dan 64K TEGELIJK besturen, met behulp van slotschakeling + kan de Z80 veel meer geheugen aanspreken. + Aangezien het slotschakelen redelijk ingewikkeld is en voor + de beginnende programmeur niet echt nodig zullen we deze + techniek pas later behandelen maar nu de indeling van de + eerste 64K bespreken. + + De eerste 32K die bij het opstarten van je MSX door de + computer bestuurd worden zijn ROM. + ROM wilt zeggen Read Only Memory, geheugen dat alleen maar + door de computer gelezen kan worden. + Dit geheugen bevat de BASIC en de BIOS en kan niet door een + programmeur beschreven worden en loopt van &H0000 tot &H7FFF. + Het onderste gedeelte van het ROM (&H0000 tot &H3FFF) + bestaat uit BIOS en van &H4000 tot &H7FFF is BASIC. + + De tweede 32K, dus het geheugen van &H8000 tot &HFFFF, is + RAM. In dit RAM kan je dus je programma's kwijt. + Houdt er wel rekening mee dat op &H8000 BASIC programma's + bewaard worden en vanaf ongeveer &HE000 beginnen de + opslagarray's van BASIC en BIOS. + + Nu is dit natuurlijk allemaal leuk om te weten, maar wat heb + je d'er aan ???? + + Wel, de BIOS is een verzameling van routines die door de + ontwikkelaars van MSX geschreven zijn om het leven van de + MSX-er te vergemakkelijken. Als je elke chip met eigen + routines zou moeten aan spreken, zou je maanden aan het + programmeren zijn voor een "simpele" scroll demo of zo.. + + De BIOS bestaat dus uit een rij routines die allemaal hun + eigen werking hebben. + We zullen er een paar bespreken .... + + CHKRAM: + Adres: 0000h + Invoer: geen + + Deze routine reset de MSX en vult het geheugen met de + juiste beginwaarden (SCREEN 0 en zo..) + + CHGMOD + Adres: 005Fh + Invoer: A + + Deze routine zet de gewenste screenmode aan. + Wil je dus SCREEN 5 dan laad je A met 5 en roep je + CHGMOD aan. + + CHGET: + Adres: 009Fh + Invoer: geen + + Deze routine leest een teken van het toetsen bord. + Als er geen teken wordt ingedrukt wacht de routine + tot dit wel gebeurd. + + CHPUT: + Adres: 00A2h + Invoer: A + + Deze routine stuurt een ASCII teken naar het scherm. + In A moet dus de ASCII waarde van de letter, die je + wilt sturen staan. + + LPTOUT: + Adres: 00A5h + Invoer: A + + Deze routine stuurt een ASCII teken naar de printer. + Als het lukt om een teken te sturen zal de CARRY vlag + laag staan. Anders is de uitvoer mislukt. + + BEEP: + Adres: 00C0h + Invoer: geen + + Roep maar eens aan !!! En sta versteld van het + resultaat. + + GTTRIG: + Adres: 00D8h + Invoer: A + Uitvoer:A + + Met deze routine test je of er een vuurknop of de + spatie balk wordt ingedrukt. + De mogelijke waarden van A, bij de invoer kunnen zijn + + 0 spatiebalk + 1 1e vuurknop joystick (of muis) 1 + 2 2e " " " " " " 1 + 3 1e " " " " " " 2 + 4 2e " " " " " " 2 + + Bij het verlaten van de routine staan de volgende + mogelijkheden: + + 00h niet ingedrukt + FFh wel ingedrukt + + FORMAT + Adres: 0147h + Invoer: geen + + Deze routine doet hetzelfde als een _format in BASIC + + Met al deze wetenschap kunnen we nu natuurlijk enige + routines schrijven. + + ORG &HC000 + + CHGMOD:EQU &H5F + CHGET: EQU &H9F + CHPUT: EQU &HA2 + BEEP: EQU &HC0 + GTTRG: EQU &HD8 + CHKRAM:EQU &H00 + + LD A,0 + CALL CHGMOD + CALL CHGET + LD (PLACE),A + CALL CHPUT + LD HL,TEXT + LD (TXTPNT),HL + + LOOP: + LD A,0 + CALL GTTRG + JP NZ,EINDE + LD HL,(TXTPNT) + LD A,(HL) + CP "$" + JP Z,EINDE + LD (TXTPNT),HL + CALL CHPUT + CALL BEEP + JP LOOP + EINDE: + JP CHKRAM + TXTPNT: + DEFW TEXT + TEXT: + DEFM "Hallo Computeraartje. Je hebt net een " + PLACE: + DEFB 0 + DEFM " getypt. Als deze text je niet bevalt, " + DEFM "moet je op de spatie balk duwen. Als je dat" + DEFM " doet zal je MSX je op reset springen. " + DEFM "ZO, GENOEG TEXT ..... LATEN WE MAAR EENS " + DEFM "RESETTEN !!!!!!!!$" + + END + + Zo dat is dan de eerste keer dat we een grote routine + publiceren en het zal niet de laatste keer zijn .... + Deze routine wacht op invoer via de BIOS routine CHGET. + Hierna zal de routine beginnen met een tekst te printen. + + Boven de programmalisting staat een aantal maal EQU, + dit is geen commando maar en komt dus ook niet in het + geheugen te staan. + De assembler vervangt na deze reeks EQU's de labels die + ervoor staan door het getal erachter. + Wordt nu b.v een CALL BEEP gedaan voert de computer een + CALL &HC0 uit. + + Het CP commando in deze routine trekt vande inhoud van het + A register het Asciiteken $ af. Wanneer nu in A het + dollarteken komt, levert deze aftrekking nul op. + Het JumP Zero commando in de volgende regel zorgt er nu voor + dat er naar het LABEL : EINDE wordt gesprongen. + Door CP wordt de inhoudt van het A register niet veranderd. + + Hopelijk verdient de rest van de instructies geen uitleg, + anders bel je gerust de programmeer lijn maar eens. + ( zie helplines ) + + Zo, dank zij de terug blader optie kan je alles nog eens + mooi overlezen. Nu kun je eindelijk eens iets meer met je + MSX dan alleen maar optellen en zo.. + + In de volgende cursus zullen we nog wat instructies + behandelen en nog wat BIOS. Misschien beginnen we daarna wel + met de besturing van de VDP of de DISK-DRIVE in MCODE. + + In elk geval, + Veel succes namens: + Ruud Gelissen en + Jan-Willem van Helden + + + Als boeken raden wij aan: + + MSX-HANDBOEK VOOR GEVORDERDEN -- A.RENSINK -- KLUWER + TECHNISCHE + BOEKEN + + ZAKBOEKJE Z80 -- J.B.VONK -- KLUWER TECHNISCHE BOEKEN + + MACHINETAAL Z80 -- J.B.VONK/E.J.J.DOPPENBERG -- KLUWER + TECHNISCHE + BOEKEN + + ASCII TECHNICAL DATA-BOOK -- ASCII Systems Division -- + ASCII CORPERATION + + diff --git a/future_disk/04/machinetaal_5.md b/future_disk/04/machinetaal_5.md new file mode 100644 index 0000000..0515507 --- /dev/null +++ b/future_disk/04/machinetaal_5.md @@ -0,0 +1,287 @@ + + Machinetaal cursus deel 5 + + Na alle mooie informatie in de vorige afleveringen + gaven we jullie in de vorige aflevering (deel 4) de + eerste grote listing. Gelukkig klopt onze programmeer + cursus tot hier toe nog helemaal want we hebben nog geen + boze reacties via onze programmeer-lijn gehad. + + Overigens excuses voor de nogal snelle behandeling van + EQU en CP, de schrijver van het stukje (JWVH) had niet + gecontroleerd of alle gebruikte commando's in de listing + behandeld waren. Daar Ruud Gelissen het stuk pas op de + clubdag in Elsloo te zien kreeg (de deadline dus) is er + toen snel nog enige tekst toegevoegd. We hopen dat dit + in de toekomst niet meer voorkomt (red.). + + Vanwege bovenstaand verhaal behandelen we EQU en CP nog + een keer, maar nu wat uitgebreider. + + EQU: + + EQU is niet de nieuwe Europese munteenheid, maar de + betekenis is wel bijna hetzelfde. In het Engels betekent + het namelijk ,"maak gelijk aan" (EQUate). Voor de munten + betekent dat dus dat ze gelijk gemaakt worden aan een + standaard, voor de computer betekent dat, dat het + ervoor staande LABEL overal in de listing vervangen + wordt door het achter de EQU staande cijfer. + + Voorbeeld: + + KOEN: EQU 6 + DOLS: EQU 3 + + LD A,KOEN + LD B,DOLS + ADD A,B + RET + + KOEN wordt nu overal vervangen door 6, + DOLS wordt nu overal vervangen door 3, dus in het + geheugen zal staan: + + #3E,#6 ; LD A,6 + #05,#3 ; LD B,3 + #80 ; ADD A,B + #C9 ; RET + + Je ziet, EQU is geen commando en wordt dus niet in het + geheugen geplaatst. + + P.S. het teken "#" is hetzelfde als "&H" en betekent + dus dat de hexadecimale notatie wordt gebruikt. + Sommige assemblers maken gebruik van het "#". + + CP: + + CP staat voor het Engelse ComPare, wat vergelijk + betekent. Het vergelijkt de inhoud van de Accumulator + (register A) met die van de waarde die achter de + instructie staat en zet aan de hand van de uitkomst de + vlaggen. CP 251 trekt dus 251 van A af maar zet de + uitkomst niet terug in A. Als A nu gelijk aan 251 is, + is de Z vlag geset ( 1 dus ) en de C vlag niet ( ** ). + Is A kleiner dan 251, dan is de C vlag geset, de Z vlag + niet. Is A groter dan 251, is de Z vlag gereset en de + C vlag ook. + + ** : De C vlag of CARRY vlag wordt dus geset als een + berekening een "foutje" opleverde. + b.v. LD A,100 of: LD B,255 + SUB 110 INC B + + of: LD A,#10 (=16) ect. + CP 17 + (voor een overzicht van de vlaggen zie FUTURE-DISK #0 + (public domain)). + + Nu het complete overzicht van CP: + + CP s + + Trekt de door s te specificeren operand af van de inhoud + van de accumulator. Het resultaat wordt genegeerd maar + beinvloed wel de vlaggen. + + s kan zijn: r,n,(HL),(IX+d) of (IY+d) + + r: + De accumulator wordt vergeleken met een van de registers + of met zichzelf. + r kan dus zijn: A,B,C,D,E,H of L + + n: + Een getal varieerende van 0 to 255. + + (HL): + Met de inhoud waarheen het adres HL verwijst. + + (IX+d): + Met de inhoud waarheen het adres IX plus verplaatsing d + verwijst. + + (IY+d): + Met de inhoud waarheen het adres IY plus verplaatsing d + verwijst. + + Oke, dit stukje is gedeeltelijk overgeschreven uit het + zakboekje Z80 Machinetaal door J.B.Vonk, omdat het + hierin het duidelijkst en goed beschreven staat. Dit + even voordat andere instanties hierover problemen gaan + maken ! + + + Al eerder zijn de POINTER register genoemt maar nog + niet uitvoerig besproken. + + IX en IY + + IX en IY zijn bijna gewone 16-bits registers als DE en + BC, ware het niet dat zij nog een speciale functie + hebben. Je kunt bijvoorbeeld register A laden met + (IX+10). Nu komt in A de inhoud van geheugenplaats 10 na + het adres waar IX naar verwijst. Het klinkt moeilijk, + maar kijk eens naar dit voorbeeldje. + + LD IX,TRASH + LD A,(IX+0) + TRASH: + DB 0 + DB 1 + DB 2 + DB 3 + + Nu komt in A dus 0 te staan. Vervangen we nu LD A,(IX+0) + door LD A,(IX+1), dan komt er in A 1 te staan. IX wordt + daarom altijd aan geduid met de verplaatsing d (IX+d). + d kan een waarde van 0 to 255 aannemen. + + Dit gehele verhaal geldt ook voor IY. + + Ook zagen we een aantal keer (HL). Dit is te vergelijken + met (IX+0). + + Met deze instructies kunnen we ook INCreasments en + DECreasments uitvoeren. INC (IX+143) is dus gewoon + mogelijk. Dit opent veel nieuwe mogelijkheden voor + professionele programmeurs (Databases,spreadsheets etc.) + Voor de demo en spelletjes programmeur zijn ze niet zo + interessant vanwege hun traagheid. Het INCreasen + (taalverloedering) van A duurt 4 T-cycli (computertijds + eenheid). INC (HL) duurt 11 T-cycli en INC (IX+d) duurt + maar liefst 23 T-cycli (bijna het 6 dubbele van INC A). + Dit wil natuurlijk niet zeggen dat je ze niet moet + gebruiken. Soms zijn ze onmisbaar, zoals in muziek + routines, want wil je het anders schrijven, kost het je + veel en veel meer geheugen. Zo zie je maar, vaak is + programmeren een kwestie van kiezen tussen snelheid of + geheugen besparing. + + P.S. traag moet hier eigenlijk tussen "aanhalings- + tekens" staan, een computer commando is nooit echt + traag. + + Een T-cycli is 1 puls van de ingebouwde klok van de + processor: Op de Z80 is dat 4 Mhz (afgerond). + 1 T-cycli duurt dus 1/4*10e6 = 2,5*10e-7 = 250 nanosec. + + Op de Turbo R draait het interne klokje met een snelheid + van 28 Mhz. Hier duurt 1 T-cycli dus 1/28*10e6 = + 3,5*10e-8 = 35 nanosec. (dat is snel !!!, dat lijkt ... + wel !!!). Maar dit is allemaal een beetje al te + technisch, want zodadelijk beginnen we over zaken die + wij niet snappen... (zoals interne struckturen of + zoiets). + + De Z80 kent ook nog de logische instructies. + Voor de vergevorderde BASIC programmeur zijn ze + misschien al bekend, maar voor het gros van de MSX-ers + is het Latijn (of Chinees voor de Latinisten). + + Het zijn: OR,XOR en AND. + + De officieele notatie is OR s, waarbij s hetzelfde kan + zijn als bij CP (zie boven). + + OR B voert een OR uit op A met de inhoud van B en zet + het resultaat in A. De logische functies vergelijken 2 + getallen binair bit voor bit met het volgende resultaat. + + A 0101 0101 + s 1001 0111 + + A OR s 1101 0111 + De OR(of) functie maakt een bit 1 als in A of in s er 1 + staat of als ze beide 1 zijn. + Voor AND(en) geldt dat beide bits 1 moeten zijn wil de + uitkomst 1 zijn. + + A 0101 1110 + s 1001 0110 + + A AND s 0001 0110 + + De XOR (eXclusive OR) doet hetzelfde als OR, maar niet + als beide bits 1 zijn. + + A 1001 0101 + s 0110 1110 + + A XOR s 1001 1011 + + Met deze instructies kun je bits testen, of setten. + Let op: XOR A geeft 0 (kijk maar na!) + XOR 255 Inverteer A + + Voor iedereen met Natuurkunde in zijn pakket of op + school, dit allemaal gaat ook behandeld worden als + onderdeel van fysische informatica. Door er nu al mee om + te gaan is het dan gemakkelijker te begrijpen. + + Om bits te setten of resetten zijn er ook de + instructies: + + SET en RES + + SET b,m + + Set het door b te specificeren bit van de door m te + specificeren operand. + m kan zijn: r,(HL),(IX+d) of (IY+d). + + SET 1,A + + Bit 1 van register A staat nu op 1. + + Bij RES geldt natuurlijk het omgekeerde. De bits worden + nu op 0 gezet. + + Nog een listinkje to slot: + + ORG #A000 + + XOR A ; in A staat 0 + LD B,A ; in B ook + LOOP: + DEC A ; A wordt verlaagd (*) + INC B ; B wordt verhoogd + JP NZ,LOOP ; in A en B staat 0 + SET 3,A ; in A staat %0000 1000 + SET 5,B ; in B staat %0010 0000 + OR B ; in A staat %0010 1000 + LD C,A ; in C staat %0010 1000 + LD A,B ; in A staat %0010 0000 + AND C ; A AND C + LD (GENIC),A ;in ZOOI komt %0010 0000 + RET ; terug naar ?? + GENIC: + DB 0 + END + + Opmerking: # en % staan voor resp. Hexadecimaale en + Binaire getallen. + + *: Als nul verlaagd wordt met 1 wordt het 255 (de + routine voert dus 256 x deze loop uit). + + De listing slaat natuurlijk nergens op, maar we hopen + dat je de logische functies hierdoor een beetje beter + begrijpt. + + Volgende keer wordt het misschien eens tijd voor een + scroll of zoiets, want nu zijn alle basis begrippen + besproken. + + Veel succes en plezier namens: + Ruud Gelissen + Jan Willem van + Helden. + + Met dank aan: + Zakboekje Z80 J.B. Vonk + Machinetaal Z80 J.B. Vonk en + E.J.J. Doppenberg + + diff --git a/future_disk/05/machinetaal_6.md b/future_disk/05/machinetaal_6.md new file mode 100644 index 0000000..d16ebb6 --- /dev/null +++ b/future_disk/05/machinetaal_6.md @@ -0,0 +1,168 @@ + Welkom bij machinetaal cursus deel 6. + + Wat zullen we vandaag weer eens vertellen. + Voorstel van R.G.: Hoe werkt basic + J.W. : NEEEEEE ! + R.G. : De stack ? + J.W. : vooruit dan maar. + + Het SP-register (STACK-POINTER). + + Kort samengevat zou je het SP-register kunnen aanduiden + als een register dat de plaats in het geheugen aangeeft + waar allerlei adressen worden opgeslagen. + Wat gebeurt er nu eigenlijk als je een CALL geeft ? + Eerst wordt het adres waar SP heen verwijst gevuld met + het adres waar bij een RET heen moet worden teruggekeerd, + dan wordt het SP-register verlaagd met 2, zodat het het + een nieuw adres aangeeft waar bij een nieuwe CALL het + adres weer kan worden opgeslagen, uiteindelijk wordt een + JP naar het te CALLen adres uitgevoerd. + + Het SP-register kan ook worden gebruikt voor het opslaan + van andere registers, waarvan men later de waarde weer + nodig heeft. + + Een PUSH HL zorgt er bijvoorbeeld voor dat de inhoud van + HL wordt opgeslagen in de geheugenplaats waarheen SP + wijst. M.B.V een POP HL wordt deze inhoud weer herstel + naar zijn oude waarde, maar een PUSH HL en een POP DE + mag ook best, zo kan men dus gemakkelijk HL in DE + "overladen". + + Pas altijd een beetje op met het gebruik van SP ! + Laat een stapel (STACK) nooit te veel groeien, de stapel + wordt van boven af naar beneden in het geheugen opgebouwd + en wijst bij het opstarten van je MSX meestal de boven- + grens van het vrije geheugen aan (ergens in de #Fxxx, + hangt af van b.v. het opstarten met of zonder CTRL-toest + ingedrukt ); zou je nu een programma maken waarbij niet + elke CALL wordt afgesloten met een RET zou deze stapel + steeds lager in het geheugen terecht komen en b.v je + programma kunnen overschrijden........ + + Let er bij het gebruik van SP verder nog op dat het + laatste op de stapel gekomen getal/adres er het eerste + er weer afgaat, programmeer dus zo : + + PUSH AF + PUSH HL + PUSH DE + PUSH BC + PUSH IX + PUSH IY + + POP IY + POP IX + POP BC + POP DE + POP HL + PUSH AF + + P.S. Dit zijn alle mogelijke vormen van PUSH en POP. + P.P.S Je ziet wel dat m.b.v een PUSH AF ook de + vlagstatus wordt opgeslagen. + P.S.S.S.De STACK wordt in BASIC o.a. gebruikt voor het + opslaan van terugkeeradressen bij een GOSUB + + TIP: + Wil je er zeker van zijn dat de stapel bij b.v. de + terugkeer naar basic weer zijn oude waarde heeft (het + adres waar basic wordt gestart) gebruik dan: + + LD (STACK),SP ; aan het begin + LD SP,(STACK) ; aan het einde + STACK: DW 0 + + + Het R-Register.(Refres-Register) + + Het R-register is een soort klokje dat razensnel tot 128 + telt en dan weer overnieuw vanaf nul begint. + Je kunt R maar op 2 manieren gebruiken : + + 1. LD A,R + 2. LD R,A + + R kan dienen als RANDOMIZER m.b.v LD A,R krijg je in A + in soort RANDOM getal, let wel op dat bit 7 altijd nul is + , wil je b.v. in A een RANDOM kleur gebruik je : + + LD A,R + AND %00001111 + + In A staat nu een willekeurig getal van 0 to 15. + + Hooks. + + Letterlijke vertaling luidt : HAKEN en deze benadert + redelijk de betekenis. + Een HOOK is een opeenvolging van 5 bytes in het RAM die + normaal allemaal met RET (#C9) gevuld zijn. + Deze "RAMHAKEN" zijn speciaal voor de programmeur + toegevoerd aan het werkgeheugen van BASIC en worden + aangeroepen op verschillende tijdstippen, afhankelijk + van de HOOK. + + Als we nu die 5 bytes vervangen door andere waardes kan + de hook plotseling iets anders gaan doen dan alleen maar + te RETten, je zou er b.v. een JP naar een ander adres in + het geheugen kunnen zetten waar je eigen routine begint, + of een JP naar een BIOS routine. + + Een voorbeeltje: + De ROM-routine die een teken op het scherm zet (CHPUT) + , geeft een CALL naar de HOOK op #FDA4 in het geheugen. + Stel nu dat je alle tekens die op het scherm komen ook + naar de printer wil sturen, de BIOS-routine die een + teken naar de printer stuurt is #A5 (LPTOUT). + Je kunt dit dus doen door in de HOOK een JP naar #A5 te + zetten. + Het JP commando bestaat uit 3 bytes. + 1. #C3 voor de computer aan te geven dat er een JP gaat + plaats vinden. + 2. #xx waarbij xx staat voor het lagere deel (!) van het + adres waar naartoe gesprongen gaat worden + 3. #xx waarbij xx staat voor het hogere deel van het + adres waar naartoe gesprongen gaat worden. + Een JP naar #00A5 moet dus zo in het geheugen gezet + worden: #C3 #A5 #00 + M.b.v het volgende programma kan de HOOK dan worden + "omgebogen": + + LD A,#A5 + LD (#FDA4+1),A ; of #FDA5 + XOR A ; = LD A,0 allen sneller + LD (#FDA4+2),A + LD A,#C3 + LD (#FDA4),A + RET + + Je ziet dus dat je het beste als laatste het #C3 + commando kunt geven, omdat anders de HOOK misschien nog + aangeroepen kan worden voordat je het juiste adres hebt + neergezet en de computer dan een JP #C9C9 zou uitvoeren. + + Tot zover deze machinetaalcursus, volgende keer zullen + we je o.a. uitleggen hoe het INTERUPT-systeem van je MSX + in elkaar zit en hoe je dit m.b.v. een HOOK kunt + gebruiken voor talrijke doeleinden. + Nu zullen je we alleen nog even zeggen welke HOOKs je + hiervoor kunt gebruiken: #FA9A of #FD9F (je ziet 5 bytes + verder in het geheugen. + Een andere HOOK die we nog even wilden noemen is: + #FDD1, die wordt aangeroepen aan het begin van de + routine die enkelvoudige toetsaanslagen verwerkt. + M.b.v. deze HOOK kun je b.v. een toetsaanslag voor een + ander doeleinde gebruiken. + + Dat was het dan weer (ja, ik begin nu niet weer met een + heel verhaal onder het motto: dat wilden we nog even + zeggen Jan-Willem.), niet meer deze keer. + + Veel programmeerplezier : Jan-Willem van Helden + Ruud Gelissen. + + p.s. leest iemand ooit deze tekst ? + + diff --git a/future_disk/05/special_effects_basic.md b/future_disk/05/special_effects_basic.md new file mode 100644 index 0000000..e7a92f3 --- /dev/null +++ b/future_disk/05/special_effects_basic.md @@ -0,0 +1,216 @@ + SPECIAL EFFECTS BASIC + -------- # 1 -------- + + Dit keer nog een soort cursus, niet over het gewone huis,tuin + en keuken BASIC, maar over het BASIC met wat verdere + bedoelingen: spellen, demo's, gebruikersprogramma's, enz. + enz. + + De naam special effects klinkt nog al proffesioneel. Het is + dus niet een cursus over de comando's PRINT, CLS, SCREEN .. + enz. Ik wil het dan ook in deze eerste aflevering hebben over + het zelf maken van letters (en natuurlijk gebruiken in eigen + programma's) en kleuren. + + LETTERS + ------- + + Om de letters op het beeld te printen kun je gebruik maken + van : + + SCREEN 5 : OPEN"GRP:"AS#1 : PRINT#1,"" + + Dit is een standaard comando dat bijna iedereen kent. Maar + als je nu zelf letters wilt gaan maken, in een tekenprogramma + of gewoon in basic, is dat een stuk moeilijker op het beeld + te printen. Je hebt hierbij een paar comando's nodig : + + A=LEN(A$) : In A komt de lengte van A$ te staan. + Bijvoorbeeld : A$="FUTURE" dan is A 7. + + A$=MID$(B$,A,B) : In A$ komt te staan : de lengte B, A + posities ver, van B$ . + Bijvoorbeeld: B$="FUTUREDISK 5",A=7,B=4 + dan staat in A$ "DISK". + + A=ASC(A$) : In A komt de ASCII waarde van A$ te staan. + Als de lengte van A$ (LEN(A$)) > ��n, + dan komt in A de ASCII waarde van de eerste + letter te staan.Dus als A$="FUTUREDISK" is + dan staat in A 70 (de ASCII waarde van "F") + + SET PAGE A,A : Wisselt van pages.In A staat het + PAGENUMMER.(geldt alleen voor screen 5 en + hoger.) + + COPY(A,B)-(C,D) : Met dit comando copi�er je van A,B tot C,D + ,G TO (E,F),H,AC uit page G naar E,F uit page H. + i.p.v AC (Ander Commando) moet je : + + PSET,PRESET,XOR,OR,AND,TPSET,TPRESET,TXOR,TOR,TAND + + zetten. Wat al deze commando's betekenen, + ga ik nu niet uitleggen.(Kijk maar eens in + het boek dat bij de computer zit onder het + hoofdstuk LOGISCHE OPERATIES). + De functie van de z.g.n LOGISCHE OPERATIES + achter een COPY invoer is dat je iets over + elkaar kunt copi�ren zonder dat hetgene + waar je overheen copi�ert weg gaat. + + Nu maar eens een programma : + + 10 color 15,0,0:screen5 :'maak altijd de achtergrond 0! + 20 set page 1,1: close: open"grp:"as #1 + 30 preset (0,0):print #1, "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + 40 set page 0,0 + 50 a$="FUTUREDISK ISSUE VIJF" + 60 for a = 1 to len(a$) + 70 b$= mid$ (a$,a,1) + 80 b= asc (b$) + 90 b=b-65 : b=b*8 + 100 copy(b,0)-(b+7,8),1 to (c,d),0 + 110 c=c+8 : next a + 120 goto 120 + + Regel 90: De ASCII waarde in B is altijd groter dan 64 (65 = + ASCII waarde "A") De "A"-"Z" in page 1 staan op positie 0,0. + Als je dus de letter A uit page 1 wilt copi�ren, moet B met + 65 worden afgetrokken.Maar als je "B" wilt copi�ren, krijg + je de positie 1,0 , terwil de "B" op 8,0 staat.Er moet dus + met 8 vermenigvuldigd worden. + + Regel 110 : Als je van C een constante zou maken, zouden + alle letters uit A$ op een plaats dus overelkaar gecopi�erd + worden.Dit is niet de bedoeling dus moet C iedere keer met 8 + (de lengte van een letter) worden opgeteld. + + De letters uit dit programma zijn standaard. Je kunt zelf ook + letters tekenen in een tekenprogramma. Je kunt ook andere + afmetingen gebruiken , dan is een kleine wijziging nodig. + Maar als echte BASIC programmeur wil je zelf letters in BASIC + maken. + We gaan nu dikke letters met 7 verschillende kleuren maken. + Het principe berust hierop: zet 7 keer de letters A-Z onder + elkaar, steeds met een andere kleur.Als je nu de tweede + lijn van de tweede regel op de tweede lijn van de eerste + regel copi�ert en de derde lijn van de derde regel op de + derde lijn van de eerste regel copi�ert ENZ.ENZ., krijg je + in de eerste regel 7 verschillende kleuren. + Als je ze nu deze eerste regel dikker wilt gaan maken, + gebruik je het bovenstaand beschreven commando + COPY(A,B)-(C,D),G TO (E,F),H,TPSET (in dit geval TPSET, + want dit "achtervoegsel" zorgt dat je iets over elkaar heen + kunt zetten, zonder dat hetgene waar je overheen copi�ert + weg gaat.) Dit is ideaal, want we willen de eerste regel + over de eerste regel heenzetten, ��n positie verder.(Dit is + het principe van letters dikmaken.) We doen dus : + + COPY(0,0)-(254,8),1 TO (1,0),1,TPSET + + In een programaatje wordt dit alles : + + 10 color 1,0,0 : screen 5 + 20 set page 1,1 : open"grp:" as #1 + 30 fora=0to7:preset (0,a*8):?#1,"ABCDEFGHIJKLMNOPQRSTUVWXYZ" + 40 color a+2:next a + 50 fora=0to7:copy(0,a*8+a)-(255,a*8+a)to(0,a) + 60 next a + 70 'letters in regel 1 hebben 7 kleuren + 80 copy(0,0)-(254,8) to (1,0),,tpset + 90 'letters in regel 1 dikker gemaakt + 100 'laad nu vorige programma en doe dan SCREEN5 : GOTO 40 + + Als U nu denkt van "Moet ik dat nu allemaal gaan intypen" dan + heeft U het mis. Op deze diskette staat het programma + BASICKS1.LDR . Als u dit runt, ziet U alle voorbeelden die + hier besproken worden. + + KLEUREN + ------- + Als U nu de kleuren van de letters niet mooi vindt, kunt U + die veranderen met : + + COLOR=(A,B,C,D) : A = kleurnummer (0-15) + B = tinten rood (0-7) + C = tinten groen (0-7) + D = tinten blauw (0-7) + + Als je bijvoorbeeld bij de vorige programma de kleuren 1-7 + hebt gebruikt en je wilt ze laten vari�ren van donker naar + licht rood (bijvoorbeeld) dan doe je dus : + + FOR A = 1 TO 7 : COLOR = (A,A,0,0) : NEXT A + + (de kleur en de kleur tint zijn het zelfde dus kun je twee + keer A gebruiken want : color 1 heeft 1 tint rood , color 2 + heeft 2 tinten rood enz.) + + Dit is wel leuk maar er zijn veel leukere dingen te doen.Ik + zal 3 programa's bespreken. + + ZEEPBEL + ------- + In het programma worden er met het commando RND gewerkt. + + A=INT(RND(B)*C) : In A komt : Random van B (Random is + willekeurig) Als B dus 1 bevat krijg je + allemaal willekeurige getallen van 0 tot 1 + In C komt een getal te staan dat aangeeft + hoeveel getallen er mogelijk zijn. INT + betekend gewoon afronden op het + dichtsbijliggende natuurlijke getal. + Als B=1 en C=10 dan staat in A een + willekeurig getal van 1 tot en met 10. + + In ZEEPBEL worden 15 cirkels getekend op met RND bepaalde + co�rdinaten met RND bepaalde tussenruimte.Iedere cirkel heeft + een kleur van 1-15 (0 = achtergrond). De kleinste cirkel + heeft kleur 1, de �nerkleinste kleur 2 enz. + Als je nu alle kleuren 0,0,0 maakt (zwart en gelijk aan + achtergrond) dan zie je dus niets. Als je nu kleur 1 wit + (7,7,7) maakt en de rest zwart, dan kleur 2 wit en de rest + zwart , dan kleur 3 wit en de rest zwart enz. enz., dan + zie je dus dat er als het ware een cirkel naar voren komt.Als + je nu van kleur 15 naar kleur 1 springt dan lijkt het net als + of de cirkel kapot springt (het ZEEPBEL effect). + (ZEEPBEL en de twee volgende programma's staan ook in + BASICKC1.LDR) + + FUTUREDISK INTROLOGO + -------------------- + + Dit programmaate bootst de intro van (deze) FUTUREDISK na. + De intro met het rollende licht wel te heten. De tekening + staat in een .DAT file en deze laden we in in PAGE 1. + We maken nu alle kleuren (0 uitgezonderd) donkerblauw (0,0,1) + Dit kan door : + FOR A=1 TO 15 : COLOR =(A,0,0,2) : NEXT A + + Dan wordt de tekening uit PAGE 1 gecopi�rt naar PAGE 0 en + wordt net als bij ZEEPBEL eerst kleur 1 wit gemaakt en kleur + 2-15 donkerblauw enz.Doordat BASIC in dit programma nog al + snel functioneerd krijg je een soort Machine Taal effect. + + + COUNT + ----- + + In het laatste programma COUNT wordt afgeteld van 9 tot 0. + We laden ook hier weer een .DAT file in. Alle kleuren worden + zwart gemaakt en het aftellen begint.Als U spatie drukt , + komt het 2e deel van COUNT. Nog een keer wordt er afgeteld , + nu in digitale cijfes. + + Zo zie je maar weer dat je met een simpel commando als COLOR + =(A,B,C,D) leuke programaatjes kunt maken.Ik hoop ook dat ik + de ANTI-BASICers een beetje heb kunnen overtuigen dat BASIC + niet alleen iets is voor domme zielepootjes. Grote spellen + zullen inderdaad niet snel genoeg werken in basic (zonder + R800), hier heb je toch Machinetaal voor nodig. + + In de volgende SPECIAL EFFECTS BASIC zal ik aandacht besteden + aan SPRITES en er zullen ook weer de nodige programma's bij + zitten. Ik hoop dat het leerzaam was. Volgende keer meer! + + Tom Wauben diff --git a/future_disk/06/machinetaal_7.md b/future_disk/06/machinetaal_7.md new file mode 100644 index 0000000..b46b1f1 --- /dev/null +++ b/future_disk/06/machinetaal_7.md @@ -0,0 +1,203 @@ + + Machinetaal Cursus Deel 7 + + Hoera, 1 jaar FutureDisk. Dat betekent ook 1 jaar de + machinetaal cursus. We hopen dat je er iets aan gehad + hebt en nu toch al een beetje gevorderd bent. + + Deze aflevering bekijken we eens de interrupt hook. + + In BASIC bestaat het commando "ON INTERVAL GOSUB". Dit + commando zorgt ervoor dat er om een bepaalde tijd naar + een programma stukje gesprongen wordt en het hoofd- + programma onderbroken wordt. Na afhandeling van de + routine wordt het hoofdprogramma weer aangesproken + totdat er weer een INTERVAL optreed. + + Nu in machinetaal is het ook niet anders. Alleen bestaan + er hier geen commando's voor. We geven even een + voorbeeld. + + Stel je wilt een scroll die voortdurend doorgaat (De + PLUTO demo) of een muziekroutine die regelmatig speelt. + Door nu op #FD9F een JP (jouw routine) te zetten kun je + er zeker van zijn dat om de 50/60 seconden (hangt af van + je interruptfrequentie) deze routine wordt aangegeven. + + Een voorbeeldje om een routine op interrupt te zetten: + + LD A,#C3 ;de JumP instruktie + LD HL,CODE ;jouw routine adres + DI ;zet de interrupt uit ! + LD (#FD9F),A ;plaats op H_TIMI + LD (#FDA0),HL ;plaats op H_TIMI+1 + EI ;Enable Interrupt + + Na de EI zal je programma bij elke interrupt naar je + routine springen (het adres CODE). + + Ook bestaat de H_KEYI, #FD9A nog. Hook #FD9A wordt veel + vaker aangeroepen dan H_TIMI (precieze frequentie + onbekend). Deze hook moet je dan ook gebruiken voor + screensplits etc. Voor muziekroutines, scrolls e.d. + gebruik je gewoon H_TIMI. + + Deze beide hooks zijn allebei uit te schakelen door het + gebruik van DI (Disable Interrupt) en in te schakelen + door EI (Enable Interrupt). + Zodra de MSX een interrupt krijgt (de Z80 zorgt hiervoor + ) springt de computer naar adres #38. Normaal staat hier + BIOS en worden dus H_KEYI en H_TIMI afgehandeld. + Gevorderde programmeurs schakelen echter de BIOS weg + (ANMA bijvoorbeeld) en plaatsen op #38 hun eigen + interrupt afhandeling. Omdat RAM sneller is dan ROM zijn + er nu enkele mogelijkheden meer want de ROM afhandeling + is nogal erg traag. Maar dit soort truuks zijn alleen + nodig als je een megademo met vele screensplits, + line-interrupts etc. wilt maken. Maar dat is voor de + gevorderde. + + Nu dacht men eind jaren '70 bij Zilog inc. dat er + behoefte was aan meerdere interrupt modes namelijk: + + Interrupt Mode 0 (IM0) + Na een interrupt-aanvraag wacht de Z80 tot het + randapparaat een instructie op de databus plaatst. Deze + instruktie wordt uitgevoerd. Een CALL of RST geeft een + sprong naar een subroutine die met RETI moet worden + afgesloten. + Deze interrupt mode heb ik nog nooit gebruikt en ik + twijfel dan ook sterk of die ook wel in het MSX systeem + ondersteund wordt. Wie het weet mag bellen. + + Interrupt Mode 1 (IM1) + De Z80 geeft een RST #38 (call #38). Dit is dus de + normale interrupt mode waarop de MSX standaard staat. + + Interrupt Mode 2 (IM2) + (er staat in m'n boekje een lap tekst van 10 regels met + onbegrijpelijke taal. Aangezien ik deze Interrupt Mode + ook nog nooit heb zien worden toegepast plaats ik dit + verhaal niet. Voor geinterreseerden: Koop een boek over + de Z80). + + Al deze modes zijn te schakelen met de commando's IM0, + IM1 en IM2. + + Ook genereert de Z80 nog een nietmaskeerbare interrupt + (NMI). Een interne flipflop wordt gereset bij de + aanvraag van een NMI. Na elke instructie wordt deze + getest. Bij een positief springt de Z80 naar adres #66. + In de normale BIOS staat hier de afhandeling voor het + MSX systeem. + Ook bestaat de BUSREQUEST, maar die wordt op MSX niet + ondersteund. + + Zo nu weet je toch wel alles wat er aan interrupts op de + MSX te vertellen valt. Ruud had vorige keer de overige + Hooks al beschreven, dus daar verwijs ik graag naar. + + Tot slot nog een voorbeeldje: + + DB #FE ;Header voor GEN80 + DW ST,EN,ST ;(bij WBASS2 niet nodig) + + ORG #C000 +ST: + LD HL,#FD9F ;oude Hook bewaren + LD DE,HOOKST + LD BC,5 + LDIR ; zie uitleg onder + LD A,#C3 + LD HL,INTERR ;nieuwe Hook neerzetten + DI + LD (#FD9F),A + LD (#FDA0),HL + EI + LOOP: + XOR A + CALL #D8 ;wachten op spatie + JR Z,LOOP ;NZ is spatie + + RESINT: + LD HL,HOOKST + LD DE,#FD9F + LD BC,5 + DI + LDIR ;herstel hook + EI + RET + INTERR: + LD HL,(TXTPNT) + LD A,(HL) + CP "@" + CALL Z,ENDTXT ;kijk einde tekst + INC HL + LD (TXTPNT),HL + JP #A2 ;Print ASCII waarde(BIOS) + ;(de RET aan het einde + ; van deze routine keert + ; van de interrupt terug) + ENDTXT: + LD HL,TEXT + LD (TXTPNT),HL + LD A,(HL) + RET + HOOKST: + DS 5 ;opslag hook + TXTPNT: + DW TEXT ;Pointer + TEXT: + DB "Hallo Boppers, dit is een voorbeeld van" + DB "een tekst die eeuwig doorgaat totdat je" + DB "op de spatiebalk ramt. Dit staat op in-" + DB "terrupt. Voor meer info zie de Future " + DB "Disk.......... Vaarwel Moeder !@" + EN: END + + Uiteraard zijn wij niet verantwoordelijk voor de + gevolgen van bovenstaande tekst. + + Het enigste nieuwe commando dat we hier gebruikt hebben + is het LDIR commando. + M.b.v. dit commando kan men gemakkelijk delen van het + geheugen kopieren. + De officiele uitleg is : + + LDIR: LoaD Increment Repeat + Laadt de inhoud van de geheugen locatie waarnaar + registerpaar HL wijst in de geheugenlocatie + waarnaar registerpaar DE wijst. Daarna worden de + inhouden van HL en DE met 1 verhoogt en die van + teller BC met 1 verlaagd. + Als de inhoud van BC hierna niet nul is herhaalt + de Z80 de instructie. + + Soortgelijke commando's zijn: + + LDI: LoaD Increment + Deze instructie doet precies hetzelfde als LDIR + met het verschil dat de instructie niet herhaald + wordt. + + LDDR: LoaD Decrement Repeat + Ook hetzelfde als LDIR, maar HL en DE worden + verlaagd. Bij deze instructie staat in HL dus + bovengrens van het te verplaatsen gebied. + + LDD: LoaD Decrement + Valt te vergelijken met LDDR, maar wordt weer niet + herhaald. + + Met deze cursi hopen we je wat achtergrond + informatie te geven, maar echt leren doe je alleen door + zelf te doen ! + + Volgende keer gaan we eens wat rekenen en nog wat dinge. + + Veel programmeerplezier namens: + Ruud Gelissen en + Jan Willem van Helden + + Voor vragen zie de helplines. + (voor aanvragen bel ook gerust eens de programmeerlijn!) diff --git a/future_disk/06/special_effects_basic_2.md b/future_disk/06/special_effects_basic_2.md new file mode 100644 index 0000000..ae6e0ed --- /dev/null +++ b/future_disk/06/special_effects_basic_2.md @@ -0,0 +1,221 @@ + SPECIAL EFFECTS BASIC # 2 + --------------------------- + + Welkom bij alweer de tweede aflevering van SPECIAL EFFECTS. + Ik wil het in deze aflevering gaan hebben over sprites en het + POINT commando. Op het einde zal ik ook nog twee basic scroll + routines bespreken. + + SPRITES + ------- + + Je kunt sprites in delen in twee soorten : 8 x 8 matrix + 16 x 16 matrix + + 8 x 8 + + De 8 x 8 sprites worden in 8 horizontale stukken verdeeld. + Ieder stuk is eigenlijk een binair getal. Een 1 stelt een + puntje voor , een 0 een lege plaats.Dus : + + 00011000 + 00111100 + 01111110 + 11111111 + 00011000 + 00011000 + 00011000 + 00011000 + + Je hebt nu dus een pijl.Om de Sprite in het videoram te + zetten , gebruik je : + + SPRITE$(A)=CHR$(&B00011000)+CHR$(&B00111100)+CHR$(&B01111110) + +CHR$(&B11111111)+CHR$(&B00011000)+CHR$(&B00011000)+ + CHR$(&B00011000)+CHR$(&B00011000) + + De bovenstaande pijl staat nu in het videoram. + Alleen is deze scrijfwijze nogal lang. Het handigste bij + sprites is on het HEXADECIMALE talstelsel te gebruiken. + Met het (bekende) commando PRINT HEX$(&B00000000) kun je alle + codes omzetten naar hexadecimaal. + De A bij SPRITE$(A)=-- is het SPRITENUMMER. + Dit is belangrijk bij het op het scherm zetten van een + sprite!! + + Het is wel een tijdrovende en omslachtige manier om zo + sprites te maken. Veel handiger is het als je een sprite + editor gebruikt. Zo'n sprite editor staat op deze disk onder + de naam SPRITEDT.LDR + + 16 x 16 + + De 16 x 16 sprites zijn iets moeilijker te maken dan de 8 x 8 + sprites. Je neemt hier namelijk vier 8 x 8 sprites. + Dus een 16 x 16 sprite is : + A$ C$ + B$ D$ + + A$ is de eerste 8 x 8 sprite en het kwart deel links boven + in. Als je nu net zo als bij de 8 x 8 sprites de codes in het + videoram wilt zetten (en je hebt de data in A$,B$,C$,D$) dan + doe je : + + SPRITE$(A)=A$+B$+C$+D$ + + Als je bijvoorbeeld 4 pijlen (zie 8 x 8) in 1 spritenummer + wilt hebben doe je A$= + + B$=A$ : C$=A$ : D$=A$ + SPRITE$(0)=a$+B$+C$+D$ + + In spritenummer 0 staan dus nu de 4 pijlen. + + LET OP !! JE KUNT DE SPRITES ALLEEN MAAR IN HET VIDEORAM + ZETTEN ALS JE EERST SCREEN 1 OF HOGER HEBT INGESTELD. + + SPRITE OP SCHERM + + Als je de bovenstaande pijlen in spritenummer 0 op het scherm + wilt zetten ,doe je : + + 10 screen5,2 + 20 A$= + 30 b$=a$ : c$=a$ : d$ = a$ + 40 sprite$(0)=a$+b$+c$+d$ + 50 put sprite 0,(100,100),15,0 + 60 goto 60 + + Regel 10 : de ,2 betekend dat je 16 sprites op het scherm + kunt zetten (16 sprites = 16 x 16 sprites). Er zijn ook nog + andere mogelijkheden : + ,0 : 8 sprites Normale grootte + ,1 : 8 sprites Dubbele grootte + ,2 : 16 sprites Normale grootte + ,3 : 16 sprites Dubbele grootte + + Regel 50 : PUT SPRITE A,(B,C),D,E + + A is het raster,waar de sprite op staat. Meestal is het + raster gelijk aan het spritenummer. Soms, als je bijvoorbeeld + een lopend poppetje in een sprite wilt zetten, gebruik je 1 + raster en meerdere spritenummers. + B is de X co�rdinaat, C is de Y co�rdinaat, D is de kleur en + E is het spritenummer. + + TWEE SPRITES OVER ELKAAR + + Ik kan me voorstellen dat je een sprite met 1 kleur erg saai + vindt. De mogelijkheid bestaat echter dat je twee sprites + over elkaar kunt zetten , zonder dat dit gaat knipperen of + zo. Ook kun je gebruik maken van het commando + + COLOR SPRITE$(A)= + + Als je nu bijvoorbeeld de 16 sprite pijl hebt en je wilt dat + de bovenste vier regels respectivelijk kleur 1-4 hebben en de + onderste vier regels kleur 5-8 en er tussenin kleur 9. + De color sprite$ is een RASTER !!! + + 10 screen 5,2 + 20 sprite$(0)=A$+B$+C$+D$ + 30 E$=chr$(1)+chr$(2)+chr$(3)+chr$(4)+chr$(0)+chr$(0)+ + +chr$(0)+chr$(0) + 40 F$=chr$(0)+chr$(0)+chr$(0)+chr$(0)+chr$(5)+chr$(6)+ + +chr$(7)+chr$(8) + 50 color sprite$(2)=E$+F$ + 60 putsprite 2,(100,100),9,0 + 70 goto 70 + + Dat achter color sprite$ maar twee strings komen heeft te + maken met dat je met 16 horizontale lijnen werkt. E$ geeft + dus de kleuren van de 8 bovenste regels en F$ van de 8 + onderste. + Je kunt met deze kennis bv. een lopend poppetje maken. In het + programma "WALK.BAS" zie je hoe. + + POINT + ----- + + Nu iets heel anders. De volgende keer wordt er een besproken + hoe je een spel kunt maken. Een (zeer) belangrijk commando + bij en spel is : + + A=POINT(B,C) + + In A komt te staan : de kleur van de pixel met co�rdinate B + en C. + Als je dus de kleur van pixel 100,100 wilt weten in screen 5 + doe je : + + 10 screen5 + 20 a=point(100,100) + 30 screen0 + 40 print a + + Dit commando is ook te gebruiken in een IF..THEN lus. Als je + bijvoorbeeld een sprite hebt die niet verder mag dan een lijn + van kleur 2, dan doe je : + + IF POINT(A,B)=2 then + + A en B zijn de co�rdinaten van de sprite. + + Dit is heel handig bij het maken van spelletjes. Als je een + poppetje hebt dat niet door een wit muurtje mag (kleur 15) + dan kun je dat met POINT maken : + + 10 color 15,0,0 : screen 5,2 + 20 sprite$(0)= + 30 a=250 : line (0,0)-(10,211),15,bf + 40 put sprite 0,(a,100),10,0 + 50 a=a-1 : if point (a,100)=15 then a=250 + 60 goto 40 + + In dit geval begint de sprite weer op 250,100 als de witte + balk is aangeraakt. Er zijn heel veel mogeijkheden met dit + commando en bij bijna ieder programma wordt er gebruik van + gemaakt. + + SCROLL + ------ + + En dan nu iets heel anders.Twee scroll-routines in BASIC. De + �ne met hetzelfde principe als de Machinetaal scroll , de + andere met een wat meer geschikt principe voor basic. + + SCROLL 1 + + Bij deze scroll wordt een deel van een karakter uit een strig + gecopi�rd naar page 2. In page 2 wordt de scroll opgebouwd. + Dan wordt uit page 2 de tekst gcopi�erd en dan wordt weer een + stukje karakter naar page 2 gecopi�erd. Enz,enz. (Zie voor + het copi�ren van karakter de vorige SPECIAL EFFECTS) + + Er zitten een paar nadelen aan deze scroll : + + 1 als je grote letters pakt en je copi�ert dan steeds maar 1 + lijntje dan gaat de scroll veel te langzaam. + + 2 als je meerdere lijnen copi�ert,krijg je een blokkerig + effect,als er een vertraging in staat en als je er geen + vertraging in zet, krijg je een soort knipper effect. Deze + scroll staat op deze disk onder de naam "SCROLL.BAS" + + + SCROLL 2 + + Bij deze scroll wordt de tekst alvast in de pages gezet. Als + je dan als het ware de pages "afgescant" en ieder stukje naar + page 0 copieert krijg je een goede scrol. Een voorbeeld van + zo'n soort scroll is een demootje,genaamd "DOOLHOF.BAS". De + computer gaat met een vierkantje (sprite) door het + doolhof. Het gehele doolhof staat in page 1. De computer + copieert steeds een stukje uit page 1 naar page 0. + + De volgende keer meer truuks met sprites en een eerste + spelletje. Ik hoop dat de BASIC-kennis weer iets uitgebreid + is. + + Tom Wauben + diff --git a/future_disk/07/machinetaal_8.md b/future_disk/07/machinetaal_8.md new file mode 100644 index 0000000..8a168f0 --- /dev/null +++ b/future_disk/07/machinetaal_8.md @@ -0,0 +1,229 @@ + MACHINETAALCURSUS 8 + + Het schijnt dat de lezers deze rubriek niet interessant + genoeg vinden...... + Machinetaal is wel leuk. maar niet als je alleen je + optelsommetjes ermee kunt uitvoeren. Dat kun je ook in + BASIC. Ik hoop dat jullie er echter begrip voor hebben + dat je zonder de basisbeginselen niet echt iets leuks + kunt doen. + We hopen dat je ondanks dit toch doorzet want dit is het + waard !!! Zo, en nu maar eens een beetje interessanter + proberen te doen..... + + Sprites in machinetaal. + + In navolging van de BASIC-cursus volgt hier de besturing + van sprites in machinetaal + (p.s. Tom, dit gaat echt veel sneller in machinetaal). + + Het definieren van een Sprite patroon (de vorm) is + vrijwel gelijk aan de methode die in basic wordt + gebruikt. Persoonlijk gebruiken we liever de T&E-soft + sprite-editor SPEN, omdat je m.b.v het "MAKE2" commando, + eenvoudig meerkleurige sprites in data kunt omzetten die + je gewoon in je programma kunt gebruiken. + + HET SPRITEPATROON + + Hier volgt een voorbeeld van een 8*8 sprite + + SPRPAT:db %01100110 + db %01100110 + db %01100110 + db %01111110 + db %01100110 + db %01100110 + db %01100110 + db %01100110 + + Een spritepatroon definier je regel voor regel. + Elke regel stel een lijn van je sprite voor. + Een ��n (staat hier 1 Kubie?) stel een puntje voor, een + nul is een doorzichtbare plaats in je sprite. + + Met de onderstaande routine kun je de spritemode op 8*8 + zetten: + + WRTVDP:EQU #47 ; SCHRIJF VDPREGISTER + + LD A,(#F3E0) ; VDP REGISTER 1 + AND 253 ; RESET BIT 1 + LD B,A + LD C,1 + CALL #48 + + Alles wat sprites betreft staat in het VRAM (videoram). + Je kunt de Spritepatronen in het VRAM zetten m.b.v. + onderstaande routine: + + LDIRVM:EQU #5C ; LDIR NAAR VRAM + + LD HL,SPRPAT + LD DE,#7800 + LD BC,8*8 + CALL LDIRVM + RET + + SPRPAT:db %01100110 + db %01100110 + db %01100110 + db %01111110 + db %01100110 + db %01100110 + db %01100110 + db %01100110 + + 64 bytes (in registerpaar BC) worden door Ldir VRAM in + het Videogeheugen gezet op adres #7800. + Hier begint standaart de Spritepatroontabel. + Deze tabel loopt tot #7FFF, dit houdt in dat je maximaal + 256 8*8 sprites kunt definieren of 64 16*16 sprites. + Zodra deze routine uitgevoerd is staat in het VRAM je + spritepatroon. + + DE SPRITECOLOR + + Je kunt een sprite per horizontale lijn een kleur geven. + Alle "eenjes" in je patroon krijgen nu deze kleur. + M.b.v. de volgende routine kun je dit bewerkstelligen: + + WRTVDP:EQU #47 ; SCHRIJF VDPREGISTER + LDIRVM:EQU #5C ; LDIR NAAR VRAM + LD HL,SPRCOL + LD DE,#7400 + LD BC,16 + CALL LDIRVM + + + Naar het VRAM op adres #7400 worden nu de spritekleuren + geschreven. Je moet er rekening mee houden dat de + kleuren van de 2de sprite pas op adres #7410 moeten + komen te staan (dat is 16 verder !! en heeft te maken + met 16*16 sprites waarbij je 16 bytes voor de kleuren + nodig hebt.). + De kleurnummers stemmen overeen met de paletkleuren, je + krijgt dus nu een half rode, half blauwe sprite. + + Zo, kleuren en patronen staan in het Vram, nu onze + sprite nog besturen. + + LDIRVM:EQU #5C ; LDIR NAAR VRAM + + LD HL,SPRATT ; ATTRIBUTEN + LD DE,#7600 + LD BC,4 + CALL LDIRVM + RET + + SPRATT:DB 100,128,0,0 + + Na het uitvoeren van dit programmatje zien we een sprite + verschijnen op het beeldscherm. + De y-coordinaat is 100 + De x-coordinaat is 128 + In de 3de byte staat het spritenummer, in dit geval 0, + dat houdt in dat het eerste spritepatroon op het + beeldscherm verschijnt. Om de 2de sprite te zien te + krijgen moet je hier een 1 neerzetten. + Let goed op, je krijgt nu alleen het 2de spritepatroon + te zien en niet de 2de spritecolors. + De spritecolors zijn namelijk verbonden aan de + attribuuttabel. Bij de eerste 4 bytes in de + spriteattribuuttabel horen dus de eerste 8 (eigenlijk + 16) bytes in de spritecolortabel.Bij de tweede 4 bytes + in de spriteattribuuttabel horen dus de tweede 16 bytes + in de spritecolortabel enz. (#7400+16) + + Nu volgt dan een uitgebreider voorbeeld van de besturing + van 2 sprites. + + WRTVDP:EQU #47 ; SCHRIJF VDPREGISTER + LDIRVM:EQU #5C ; LDIR NAAR VRAM + DB #FE + DW ST,EN,ST + + ORG #A000 + ST: LD A,(#F3E0) ; VDP REGISTER 1 + AND 253 ; RESET BIT 1 + LD B,A + LD C,1 + CALL #48 ; SPRITES 8*8 + LD HL,SPRPAT ; PATRONEN IN VRAM + LD DE,#7800 + LD BC,8*8*2 + CALL LDIRVM + LD HL,SPRCOL ; COLORS IN VRAM + LD DE,#7400 + LD BC,16*2 + CALL LDIRVM + LOOP: + XOR A ; SPATIE ? + CALL #D8 + RET NZ ; JA, STOP + LD HL,(TABPNT) ; HAAL YCO. UIT TABEL + LD A,(HL) + LD B,A ; BEWAAR TABELWAARDE + INC A + CALL Z,REPEAT ; 255 ? JA, HERHAAL + INC HL ; VOLGENDE YCO. + LD (TABPNT),HL + LD (SPRATT),A ; ZET YCO. SPRITE 1 GOED + LD A,(SPRATT+1) + ADD A,4 + LD (SPRATT+1),A ; VERHOOG XCO. SPRITE 1 + LD (SPRATT+4),A ; ZET YCO. SPRITE 2 + LD A,B ; ZET XCO. SPRITE 2 + LD (SPRATT+5),A + EI + HALT ; WACHT OP INTERUPT + LD HL,SPRATT ; ATTRIBUTEN + LD DE,#7600 + LD BC,4*2 + CALL LDIRVM + JP LOOP + + REPEAT:LD HL,TABEL ; START TABEL + LD A,(HL) + LD B,A + RET + + TABPNT:DW TABEL + TABEL: DB 10,11,13,15,18,21,26,31,37,43 + DB 43,37,31,26,21,18,15,13,11,10,255 + SPRATT:DB 0,0,0,0 + DB 16,50,1,0 ; SPRITE NUMMER 1 + + SPRCOL:DB 15,15,15,15,15,15,15,15 + DB 00,00,00,00,00,00,00,00 ; DUMMIES + DB 15,15,15,15,15,15,15,15 + DB 00,00,00,00,00,00,00,00 ; WORDT NIET HEEN + ; GEKEKEN + SPRPAT:db %11001100 + db %00100100 + db %01111110 + db %01101011 + db %11111111 + db %11011101 + db %01100011 + db %00111110 ; EINDE EERSTE SPRITE + + db %01100110 ; 2DE SPRITE + db %01100110 + db %01100110 + db %01111110 + db %01100110 + db %01100110 + db %01100110 + db %01100110 + + EN: END + + Voer dit maar eens uit en als het goed is zul je 2 + sprites zien bewegen. Je kunt natuurlijk b.v. een + sinustabel in basic in het geheugen "poken" enz. + + Tot zover deze keer, voor special requests wendt je tot + Ray Cokes of Ruud Gelissen. + Ajuu J.W. en Ruud. Aleih gank maar es get angers leze, + manne.(Vert.: Wilt U alstublieft een andere tekst gaan lezen) diff --git a/future_disk/07/special_effects_basic_3.md b/future_disk/07/special_effects_basic_3.md new file mode 100644 index 0000000..d5ea0e1 --- /dev/null +++ b/future_disk/07/special_effects_basic_3.md @@ -0,0 +1,218 @@ + SPECIAL EFFECTS BASIC # 3 + +++++++++++++++++++++++++ + + Alweer de derde aflevering van SEB. Deze keer leert U een + uitgebreid tekenprogramma te maken. De besturing, pages enz + worden besproken . Maar eerst het tweede deel van SPRITES. + + + SPRITES #2 + ---------- + + Zoals de vorige keer bescheven zijn sprites (ltrl. GEESTEN) + handig voor gebruik in eigen programma's. Om een sprite in 't + geheugen te zetten, is er in BASIC het commando SPRITE$(A)=- + (zie vorige cursus). Er is ook een andere manier: + De data wordt in een DATA file meteen in het sprite geheugen + ingelezen. Om dit te begrijpen eerst nog een stukje theorie + over het V-ram. + In het V-ram heeft iedere screen zijn eigen geheugen. Zo is er + er geheugen voor karakters, kleuren etc. Ook voor sprites is + er in iedere screen een stukje gereserveerd. Een klein + overzichtje zal dit duidelijk maken : + + KARAKTER POSITIE TABEL (geeft de karakterposities op beeld + weer) + KARAKTERVORM TABEL (vorm van de karakters) + + KLEUREN TABEL (bepaalt kleur die elke beeldpositie heeft) + + PALET TABEL (bevat alle R-G-B tinten van iedere kleur) + + SPRITE KLEUREN TABEL (bevat de kleuren van COLOR SPRITE) + + SPRITE ATTRIBUTE TABEL (bevat info. over sprite: grootte , + positie enz.) + SPRITE VORM TABEL (bevat vorm van sprites) + + Sommige screens hebben ��n tabel niet (bv. screen 0 heeft + geen SPRITE vorm tabel). Iedere tabel gebruikt een stukje + V-ram. Het is mogelijk hierin te schijven. We kunnen dus een + sprite meteen in het geheugen poken. + Het poken in het V-ram gaat met het bevel: + + VPOKE A,B : in A staat het V-ram adres en in B de waarde. + + Om nu in het V-ram een sprite te zetten, moet je dus het + adres weten van de SPRITE-VORM TABEL in de gewenste screen. + Een sprite die je aan het begin van de tabel poked heeft + spritenummer 0, de tweede nr. 1 enz. + Het volgende programmaatje zet een sprite die de DATA in de + DATA-regels heeft staan in het V-ram (screen 5) + + 10 SCREEN 5,0 : 'een 8 sprite + 20 FOR I=0 TO 7 : '8 DATA'S + 30 READ A : 'LEES WAARDE IN A + 40 VPOKE &H7800+I,A:'HET EERSTE ADRES VAN DE SPRITE-VORM TABEL + IS &H7800. DE SPRITE KOMT DUS HELEMAAL IN HET BEGIN TE STAAN + 50 NEXT I + 60 'OPROEPEN SPRITE (=NORMAAL) + 70 PUT SPRITE 0,(128,106),15,0 + 80 GOTO 80 + 90 'DATA REGEL SPRITE (GESTREEPT VLAKJE) + 100 DATA 255,0,255,0,255,0,255,0 + + Deze manier is vooral handig bij veel sprites. Schrijf alle + data in het gewone RAM, save het weg en laad dit in het V- + ram op de juiste plaats. Dit komt nog in een volgende cursus + bod. + + Dit zelfde vehaaltje geldt voor COLOR SPRITE. + + Genoeg over sprites. We gaan nu een tekenprogrammaatje maken. + + SEB-GRAPH + --------- + + Om een eigen programma te maken zullen we eerst de besturing + d.m.v. de randapparatuur (toetsenbord,joystick enz.) + bespreken. De besturing van toetsenbord en joystick is het- + zelfde. Er zijn nl. 8 richtingen en een rust plaats. In een + schema ziet dat er zo uit : + 1 + 8 2 + 7 0 3 + 6 4 + 5 + + Richting 5 is bv. dat er naar onder is gedrukt op het toetsen + bord of joystick. + Zoals in het bovenstaande schema geeft de computer de + richtingen weer m.b.v. het commando : + + A = STICK(B) : A komt de waarde te staan (0-8 , zie + bovenstaande schema) en in B staat de poort + waarvan moet worden gelezen in B kan staan: + 0 : Toetsenbord + 1 : Joystick poort 1 + 2 : Joystick poort 2 + Let op! A is altijd een variable , B is + een constante. + + M.b.v. deze kennis kun je bv. een menuutje maken in screen 0. + Kijk maar in de onderstaande listing ; + + 10 SCREEN 0 : WIDTH 80 : KEY OFF :'INSTELLINGEN + 20 CLS : FOR I = 1 TO 5 : READ A$ : LOCATE 30,I:PRINT A$ + 'Zie onderstaande informatie + 30 NEXT I + 40 IF STRIG(0) OR STRIG (1) OR STRIG (3) THEN 110 + 50 A=STICK(0):IF A=0 THEN A=STICK(1) : IF A=0 THEN + A = STICK (2) : IFA=0 THEN GOTO 40 + 60 IF A=1 THEN Y=Y-1 : IF Y<1 THEN Y=5 + 70 IF A=5 THEN Y=Y+1 : IF Y>5 THEN Y=1 + 80 LOCATE 28,YO : PRINT " " : LOCATE 39,YO : PRINT " " + 90 LOCATE 28,Y : PRINT ">" : LOCATE 39,Y :PRINT "<" + 100 YO=Y : GOTO40 + 110 IF Y = 5 THEN END ELSE RESTORE 130 : FOR I=1 TO Y : + READ A$ : NEXT I + 120 RUN A$+"LDR" + 130 DATA MENU + 140 DATA MAGAZINE + 150 DATA DEMO + 160 DATA AUTOEXEC + 170 DATA STOP + + Een eerste langere listing. Nog even wat uitleg : + + Regel 20 : READ A$ : in a$ komt de data te staan die achter + commando DATA staat. Wordt er nog een READ A$ + gedaan dan springt de computer automatisch naar de + sting achter de komma of de string achter een + nieuwe DATA-regel (in dit geval). + RESTORE in regel 110 geeft aan waar de DATA moet + worden gelezen.(in dit geval regel 130) + + Regel 40 : hier staat een nieuw commando : + + IF STRIG (A) THEN : Dit commando gaat naar regel als + er een knop/spatie van toetesenbord , + joystick of muis wordt ingedrukt. + In A staat : + + 0 spatiebalk + 1 joystick / muis poort 1 , knop 1 + 2 joystick / muis poort 1 , knop 2 + 3 joystick / muis poort 2 , knop 1 + 4 joystick / muis poort 2 , knop 2 + + In dit geval wordt er naar regel 110 gesprongen als er spatie + of knop 1 van joyst./muis in poort 1 of 2 wordt gedrukt. + + (Dit programmaatje staat op deze disk onder de naam + "SEBMENU.LDR") + + het lezen van de besturing van de muis + -------------------------------------- + Om de muis te lezen is er ook een appart commando : + + PAD (A) : A kan 18 waardes hebben. Hier worden alleen de + waardes voor de muis in poort 1/2 besproken. + + MUIS in poort 1 : eerst de altijd PAD (12) doen. Dit is om + een de MUIS-DATA te "openen". PAD (13) + geeft de X vershuiving en PAD (14) de + Y vescuiving. + MUIS in poort 2 : hetzelfde verhaal alleen met resp. PAD (16) + PAD (17) en PAD (18) + + In het programma CUJOMU.LDR kunt u alle besproken besturings- + vormen in een programma zien. U kunt dit programma ook voor + eigen gebruik gebruiken. Dit programmaatje vormt de basis + voor het tekenprogrammaatje. + + Om te kiezen tussen de verschillende opties (lijn tekenen + enz.) maken we bebruik van IKONEN. Deze tekeningetjes worden + ingeladen in PAGE 1. (zie SEB #1). In page 2 wordt de oude + tekening bewaard. + + Het enige commando wat we nu nog niet kennen om het + tekenprogramma af te maken is : + + ON A GOSUB , , : dit commando spring naar de sub + routine die begint op regel B + als A 1 is , sprint naar regel als A 2 is enz. + + Een voorbeeldje : + + 10 D=STICK (0) : IF D=0 THEN10 + 20 ON D GOSUB 40,50,60,70,80,90,100,110 + 30 GOTO 10 + 40 PRINT "BOVEN" : RETURN + 50 PRINT "RECHTS-BOVEN" : RETURN + 60 PRINT "RECHTS" : RETURN + 70 PRINT "RECHTS-ONDER" : RETURN + 80 PRINT "ONDER" : RETURN + 90 PRINT "LINKS-ONDER" : RETURN + 100 PRINT "LINKS" : RETURN + 110 PRINT "LINKS-BOVEN" : RETURN + + Deze listing gaat dus naar regel 40 als D=1(boven). + + Nu kunnen we dus SEB-GRAPH maken. Op deze disk staat het + tekenprogrammaatje onder de naam SEB-GRPH. Bekijk gerust de + list eens. Daar leert U veel van. + + Tot slot nog een denkspelletje waarin veel van het + bovenstaande wordt gebruikt. Start het maar eens op (DENKSPEL + .LDR) en speel. Als het goed is kunt U zoiets nu ook maken. + + + Veel theorie deze keer, maar U ziet : je kunt er leuke + dingen mee maken. Volgende keer proberen we eens een echt + spelletje te maken. Is bij U al de programmeer drift + toegeslagen , stuur dan eens een eigengemaakt programmaatje + op naar het bekende FUTURE-DISK adres (zie helplines). + Heb je nog vragen , bel dan 046-758100 (na 16.00 U. Tom). + + Tom Wauben diff --git a/future_disk/075/machinetaal_cursus_9.md b/future_disk/075/machinetaal_cursus_9.md new file mode 100644 index 0000000..8c1e816 --- /dev/null +++ b/future_disk/075/machinetaal_cursus_9.md @@ -0,0 +1,204 @@ +MACHINETAAL CURSUS DEEL 9 +------------------------------- + +Na de vorige keer mooi de BASIC cursus gevolgd te hebben, +gaan we nu mooi zelf aan de slag met oersaaie, maar broodno- +dige, mcode. +Deze keer behandelen we de MSX2 SUB-ROM en de schuif- en ro- +teerfuncties. + + SCHUIF- EN ROTEERFUNCTIES +------------------------------- +De schuif- en roteerfuncties zijn bedoeld om binnen een +register de bits te verschuiven. +Schuifinstructies schuiven alle bits 1 naar rechts of 1 naar +links, roteerfuncties doen dit ook, maar roteren de inhoud +van de laagste bit in de hoogste, of andersom. +We bespreken d'er een rits (allemaal dus !!): + +* RLCA (Rotate Left Circular Accumulator) + +Roteert de inhoud van register A 1 bit naar links. De inhoud +van bit 7 komt in de Carry vlag en in bit 0. +Je kunt dus snel de inhoud van de hoogste bit van A testen +met deze instructie en dan op de carry te testen. + +* RLA (Rotate Left Accumulator) + +Doet bijna hetzelfde als een RLCA, maar de inhoud van de +Carry bit komt nu in bit 0. + +* RRCA (Rotate Right Circular Accumulator) + +Zie RLCA, maar i.p.v. naar links te schuiven schuift deze +instructie naar rechts en komt bit 0 nu in de Carry en in bit +7. + +* RRA (Rotate Right Accumulator) + +Zie RLA, maar i.p.v. naar links te schuiven schuift deze +instructie naar rechts en de inhoud van bit 0 komt in de +Carry. De Carry gaat naar bit 7. + +Tot zover de instructies die alleen op register A betrekking +hebben. Nu de rest van de instructies die je op alle 8 bits +registers te gebruiken zijn. + +* RLC r (Rotate Left Circular) + +Deze instructie doet hetzelfde als de instructie RLCA. Nu kun +je dus in alle 8 bits registers schuiven. +Ook kun je deze instructie gebruiken in de volgende formaten: +RLC (IX+d) +RLC (IY+d) +RLC (HL) +Nu schuif je dus met de inhoud van geheugenlocaties waarheen +dat 16 bits register verwijst. + +* RRC r (Rotate Right Circular) + +Deze instructie doet hetzelfde als de instructie RRCA. +Ook deze instructie werkt weer zo: +RRC (IX+d) +RRC (IY+d) +RRC (HL) + +* RL m (Rotate Left) + +Deze instructie doet hetzelfde als RLA. Werkt op alle 8 bits +registers. + +* RR m (Rotate Right) + +Deze instructie doet hetzelfde als RRA. Werkt op alle 8 bits +registers. + + +* SLA m (Shift Left Arithmetic) + +Dit is de eerste schuifinstructie. +Alle bits worden 1 plaats naar links geschoven, waarbij bit 7 +in de Carry wordt geschoven en in bit 0 komt een 0. + +* SRA m (Shift Right Arithmetic) + +Alle bits gaan 1 naar rechts. Bit 0 komt in de Carry en de +inhoud van bit 7 verandert niet. + +* SRL m (Shift Right Logical) + +Hetzelfde als SRA, maar in bit 7 komt een 0. + +* RLD (Rotate Left Digit) + +Dit is een verplaatsing van nibbles (groupies van 4 bits) +tussen register A en de inhoud van HL, (HL). De onderste +nibble van A (bit 0-3) komt in de onderste nibble van (HL). +De onderste nibble van (HL) komt in de bovenste. De bovenste +nibble van (HL) komt in de onderste nibble van A (jaja). +* RRD (Rotate Right Digit) + +Ook dit is een verplaatsing van nibbles tussen A en (HL). +De onderste nibble van A gaat naar de bovenste van (HL). +De bovenste van (HL) gaat naar de onderste van (HL). +En de onderste van (HL) gaat naar de onderste van A +(jajajaja). + +Omdat al deze instructies moeilijk te begrijpen zijn zonder +begleidende schema's, staat er op deze disk een .PTC file. +Deze kun je in Dynamic Publisher inladen. +Tenminste ......... als het oppermonster 'm niet gewist of +gecrunched heeft (RED. det is toch waardeloze zeik !!). + + HET SUB ROM + ------------- + +Aarg, er zit nog meer ROM in je MSX 2!!! Je dacht dat je met +de BIOS plus BASIC alles had, kom je bedrogen uit. De schele +makers van de MSX 2 vonden dat ze te weinig plaats hadden +voor typische MSX 2 routines. Daarom werd er nog een 16K +groot ROM gemaakt dat ergens in 1 van de slots geplaatst +werd. Omdat het slot systeem nogal moeilijk is, hebben de +programmeurs van ASCII op adres #15F een BIOS routine gemaakt +waarmee je makkelijk het Subrom kunt aansturen. +Deze routine werkt als volgt: +In register IX plaats je het adres van de Subrom routine, die +je wilt gebruiken. Een paar voorbeelden: + +GRTPRT: EQU #89 +LD A,5 +CALL #5F +LD A,"A" +LD IX,GRTPRT +CALL #15F +RET + +Deze routine print een teken op de grafische schermen 5 tot 8 +en verwacht dit teken in register A. Vergelijk in BASIC de +instructie: OPEN "GRP:" AS#1: PRINT #1,"A". + +SETPLT: EQU #14D +LD A,5 +CALL #5F +LD D,15 +LD A,%11110000 +LD E,0 +LD IX,SETPLT +CALL #15F +RET + +Deze routine verandert een kleur van je palet. In A moet je +in de bovenste nibble de roodintensiteit zetten en in de +laagste nibble de blauwintensiteit. In E zet je in de laagste +nibble de groenintensiteit. In D staat het te veranderen +colornummer. In BASIC is dit: COLOR=(15,7,0,0). + +De routine NEWPAD op #1AD kan de muis aansturen. Dit werkt +ongeveer hetzelfde als in basic. Als je de BASIC begrijpt kun +je het onderstaande machinetaalprogrammaatje ook wel +ontcijferen. + +NEWPAD: EQU #1AD +LD A,12 +LD IX,NEWPAD ;Schakel muis aan. +CALL #15F +LD A,13 ;Lees X-offset uit +LD IX,NEWPAD ;(optellen bij oude X-co.) +CALL #15F +PUSH AF ;bewaar X-offset +LD A,14 ;Lees Y-offset uit +LD IX,NEWPAD ;(optellen bij oude Y-co.) +CALL #15F +LD B,A ;Y-offset in B. +POP AF + +Voor een geheel overzicht van het Subrom kun je contact +opnemen met de programmeerlijn. + +Eigenlijk hadden we nog een mooie grote listing willen laten +zien, waarin veelvuldig gebruikt wordt gemaakt van de schuif- +en roteer instructies. Maar des te langer je er over gaat +nadenken, des te moeilijker wordt het om iets zinnings te +verzinnen. Toch nog een klein voorbeeldje: + +LD A,#F0 ;HOOGSTE NIBBLE VOL +RRCA ;IN A: %01111000 +RRCA ;IN A: %00111100 +RRCA ;IN A: %00011110 +RRCA ;IN A: %00001111 +AND %00001111 ;BOVENSTE NIBBLE WISSEN + +Soms moet je gaan rekenen met de bovenste nibble. Nu is dat +flink lastig. Daarom is het handig om de bovenste nibble in +de onderste te schuiven. De AND op het einde is eigenlijk +niet nodig, maar als er al data in de onderste nibble staat, +wordt deze doorgeschoven in de bovenste bits. + +Door een foutje werkte het programma SPRITES vorige keer +niet. Dit is verholpen en dan hopen dat in de rebount alles +goed gaat. + +Veel programmeer plezier en een prettige vakantie, + + Ruud Gelissen, + Jan Willem van Helden diff --git a/future_disk/075/special_effects_basic_4.md b/future_disk/075/special_effects_basic_4.md new file mode 100644 index 0000000..3797b5c --- /dev/null +++ b/future_disk/075/special_effects_basic_4.md @@ -0,0 +1,593 @@ +Speciale dank gaat uit naar J.B.Vonk. + + + + SPECIAL EFFECTS BASIC #4 + ------------------------ + + Welkom bij het vierde deel van Special Effects. Deze keer + (nog) een deel van sprites, de logische operaties , de uitleg + van PAC-IT , een pacman-kloon en tot slot nog het DEF FN , + ON INTERVAL en INSTR commando , een aantal losse flodders die + handig zijn bij het programmeren in BASIC .... + + + + SPRITES (4) + +-+-+-+-+-+ + + Deze keer een korte SPRITES-cursus. De volgende (en tevens + laatste) SPRITES zal een aantal truuks laten zien met + sprites. + Deze keer wordt alleen de 3 kleurige sprite uit de doeken + gedaan en nog een paar aardigheidjes met het color sprite$ + commando. + + Jazeker. Ook driekleurige sprites zijn mogelijk terwijl er + maar 2 sprites over elkaar worden gezet. Waar de 2 sprites + elkaar overlappen, worden deze ge-ORd (zie LOGISCHE OPERATIES + , hieronder). Zo kan deze 3e kleur worden berekend. U kunt + dan zelf de gewenste kleur geven met COLOR=. (zie SEB #1). + + Maar hoe wordt dit dan gedaan ?? + + De zesde bit van de colorsprite$-byte wordt geset. + Deze byte ziet er als volgt uit + + | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | + --------------------------------- + |VPb|ORb|IGb|nvt|CLR|CLR|CLR|CLR| + + + VPb (bit 7) : als deze bit geset is , wordt de sprite 32 + pixels naar links verplaatst. + + ORb (bit 6) : als deze bit geset is en twee sprites + overlappen, zal er een OR-operatie tussen deze twee kleuren + plaatsvinden en deze kleur wordt op het scherm afgebeeld. + + IGb (bit 5) : de sprite-overlapping wordt genegeerd. + + Bit 4 heeft geen functie. + + CLR (bit 0 t/m bit 3) : deze bits geven de spritekleur aan. + + + Als bijvoorbeeld de spritelijn-kleur van sprite I 12 moet + zijn en van sprite II 10 en ze moeten ge-ORd worden, dan + moet bit 6 geset zijn : + + SPRITE I : &b01001100 'bit 6 geset en kleur 12 (&b1100) + + SPRITE II : &b01001010 'bit 6 geset en kleur 10 (&h1010) + + In een list : + + 10 COLOR 15,0,0 : SCREEN 5,0 + 20 A$=CHR$(&HFF)+CHR$(&HFF)+CHR$(&HFF)+CHR$(&HFF) + 30 SPRITE$(0)=A$+A$ + 40 SPRITE$(1)=A$+A$ + 50 COLOR SPRITE$(0)=CHR$(&B01001100) + 60 COLOR SPRITE$(1)=CHR$(&B01001010) + 70 PUT SPRITE 0,(100,100),,0 + 80 PUT SPRITE 1,(104,100),,1 + 90 GOTO 90 + + De sprites worden ten opzichte van elkaar 4 pixels + verschoven. Ze overlappen elkaar dus van (104,100)-(108,100) + Daar wordt de kleur dus : + + 1100 + 1010 or + ------- + 1110 'color 14 !!! + + + LET OP !! Voor iedere sprite-lijn is een colorsprite$-bit, + dus kunt u in totaal maar liefst 32 kleuren in 2 sprites + gebruiken. + + Het aardige programmaatje SPRITES.BAS laat alle besproken + mogelijkheden nog eens zien. + + + + LOGISCHE OPERATIES + +-+-+-+-+-+-+-+-+- + + Een logische operatie is een bewerking van een + variable ,copy,enz. + + VARIABLE + -------- + + De "hoofd" logische operaties zijn de AND,OR,XOR. + + AND X Y XY OR X Y XY XOR X Y XY + + 0 0 0 0 0 0 0 0 0 + 1 0 0 1 0 1 1 0 1 + 0 1 0 0 1 1 0 1 1 + 1 1 1 1 1 1 1 1 0 + + U ziet het is dus eigenlijk een bewerking van BITs. Maar als + u nu bv. een in A staande waarde wilt ANDen dan typt U + + PRINT A AND 0 + 0 + + Er komt nu altijd nul uit , want als U met 0 AND dan komt er + altijd 0 uit (alleen als X en Y 1 zijn dan komt er 1 uit.) + + Nu zijn hier hele leuke dingen mee te doen , in BASIC zouden + er nog wel andere commando's nodig kunnen zijn bv. als X=0 en + Y=0 dan XY=1 . Daarom volgt hieronder nog een lijst(je) met + aanvullende (afgeleid van AND,OR en XOR) logische operaties. + + NOT X Y XY EQV X Y XY IMP X Y XY + + 0 - 1 0 0 1 0 0 1 + 1 - 0 1 0 0 1 0 0 + - - 0 1 0 0 1 1 + - - 1 1 1 1 1 1 + + De NOT functie is handig bij het kijken of een variable 0 is. + Van deze logische operatie kan het resultaat bekeken worden + met : + + PRINT NOT A + + De EQV is de omgekeerde XOR functie (EQV = Exclusive Or + Negative , XOR = eXlisive OR) , zoals de naam het al zegt. + + En dan het IMP commando. Zelf heb ik het nog nooit gebruikt + en ik denk dat deze logische operatie dan ook volstrekt + zinloos is. + + COPY,LINE + --------- + + Er zijn ook logische operaties m.b.t. het copie�ren en het + tekenen van een lijn. In SEB #1 is de operatie TPSET aan bod + gekomen. Hieronder volgt een lijst van alle logische + operaties bij een COPY : + + AND : Voert een AND operatie op de kleuren uit (zie VARIABLE) + + OR : Voert een OR operatie op de kleuren uit (zie VARIABLE) + + XOR : Voert een XOR operatie op de kleuren uit (zie VARIABLE) + + PRESET : Voert een INVERSE (NOT) uit op de kleuren. Iedere + bit die geset is (1) wordt 0 en iedere bit die 0 is + wordt 1. + + PSET : De normale copy. + + Ook bestaan de bovenstaande commando's met een T ervoor + (TAND,TOR,TXOR,TPRESET,TPSET). Dit betekend dat color 0 als + doorzichtig wordt beschouwd (en dat de achtergrond dus te + zien is). + + Een voorbeeldje : + + 10 COLOR 0,0 : SCREEN 5 : CIRCLE (25,25),25,10 + 20 LINE (100,100)-(200,200),2,BF : GOTO 140 + 30 COPY(0,0)-(50,50) TO (125,125),0,AND : RETURN + 40 COPY(0,0)-(50,50) TO (125,125),0,TAND : RETURN + 50 COPY(0,0)-(50,50) TO (125,125),0,XOR : RETURN + 60 COPY(0,0)-(50,50) TO (125,125),0,TXOR : RETURN + 70 COPY(0,0)-(50,50) TO (125,125),0,OR : RETURN + 80 COPY(0,0)-(50,50) TO (125,125),0,TOR : RETURN + 90 COPY(0,0)-(50,50) TO (125,125),0,PRESET : RETURN + 100 COPY(0,0)-(50,50) TO (125,125),0,TPRESET : RETURN + 110 COPY(0,0)-(50,50) TO (125,125),0,PSET : RETURN + 120 COPY(0,0)-(50,50) TO (125,125),0,TPSET : RETURN + 130 'HOOFDLUS , SPRING IEDERE KEER NAAR ANDERE COPY. + 140 D=D+1 : A$=INPUT$(1) + 150 ON D GOSUB 30,40,50,60,70,80,100,110,120 + 160 GOTO 160 + + Met dit programma kunt u alle verschillende logische + operaties zien. Bekijk bij iedere operatie de kleuren maar + eens. Dit is een zeer beknopt programma. In de file + "COPYLOG.BAS" kunt U een uitgebreider programma zien. + + U kunt deze logische operaties ook gebruiken bij het LINE + commando. Zie daarvoor "LINELOG.BAS". Kijk ook gerust eens in + de LIST. U kunt hier veel van leren. + + Genoeg over de logische operaties. U zult ook in andere + programma's deze logische operaties zien en zelfs in ML wordt + een deel ervan gebruikt. Dit komt doordat de logische + operaties erg snel zijn. Experimenteer gerust , Uw computer + heeft eindeloos gedult. + + + Deze tekst is een beetje lang , zodat hij in 2 delen + gesplitst moest worden. + + Lees verder bij het 2e deel ..... + + Special Effects Basic #4 (vervolg) + ---------------------------------- + + + + PAC-IT + ++++++ + + Al een paar keer werd het aangekondigd , maar nu beginnen we + dan toch echt met een spel , PAC-IT. Het is een kloon van het + overbekende spel PACMAN. Toch is zo'n simpel uitziend spel + nog ingewikkeld. In dit deel gaan we niet verder dan de + opbouw van het speelscherm en een deel van de hoofdlus + (lopen, happen en stoppen voor een muur.) + In de volgende SEBs komt de rest van het spel aan bod. + Maar voordat u begint te lezen zou het handig zijn de + listing bij de hand te hebben. Druk dan nu op reset , laad + de file PACIT.BAS,zet de printer aan , druk op de J , laad + daarna de file MAGAZINE.LDR en lees verder ... + + VRAAG 1 + +++++++ + + De eerste vraag is het probleem van "welke screen ?". De + screenmode wordt bij dit spel screen 5. + In deze screen kan er namelijk van een groot aantal + commando's gebruik worden gemaakt zoals SET PAGE,POINT, + COPY enz. + + Om bij het begin te beginnen , gaan we eerst eens aan de + grafische aspecten werken. Hieronder wordt verstaan : de + sprites,de achergrond,de scorelijst enz. Dit is dan ook het + begin van de listing. Meteen daarna komt de hoofdlus. Dat is + in dit geval de besturing en het happen. + + DE GRAPHICS + +++++++++++ + + De sprite(s) van PACCIE is getekend met de SPRITE-EDITOR van + futuredisk #6. Deze worden met het programaatje SPRITE.LDR + (ook van FD #6) in het V-ram ingeladen. + De scorelijst-met-cijfers- tekening is getekend in (volgens + mij) het beste screen 5-tekenprogramma : DD-graph. + Deze tekening (PACIT.DAT) is , zoals de extensie zegt , een + DAT-file (inladen m.b.v. COPY "" TO (A,B),PG). + De co�rdinaten zijn zelf opgemeten en daarmee wordt alles op + de goede plaats gezet. + + DE BESTURING + ++++++++++++ + + De besturing van PAC-IT is iets anders dan de besturing van + CUJOMU (die er niet op FUTUREDISK 7 stond, maar nu wel van + de partij is). PACCIE moet nl. altijd doorlopen (totdat hij + tegen een muur loopt). Daarom staan in variablen X en Y + respectivelijk de X en de Y STAP (!). De co�rdinaten van de + sprite zijn de variablen A en B. Deze worden dus iedere keer + met X resp. Y opgeteld. Deze X en Y stap worden weer bepaald + door de variable K. Hierin staat hoe groot de X en Y stap + moet zijn. Als u K dus verandert, zal de stap ook + veranderen. + + Ook het spritenummer wordt bij iedere verandering van + richting gegeven. Dit zou ook via een ingewikkelde formule + kunnen, maar dit is makelijker. + + MUUR ??? + ++++++++ + + POINT .. Het is al eerder gezegd, maar het POINT-commando + komt toch altijd weer aan bod. Ook bij PAC-IT neemt het een + grote plaats in nl. bij het "zien" van een muur. Er moet dan + gestopt worden. Haalt u de POINT-regels maar eens uit het + programma en alles zal in de soep lopen. + + Bij iedere beweging van de sprite wordt er gekeken of er nog + niet tegen een muur aangebotst is. Op alle 4 de hoeken van + de sprite (A,B/A+8,B/A,B+8/A+8,B+8) wordt gekeken of er geen + puntje (POINT !!) van kleur 12 zit (de kleur van de muur). + Is dit wel het geval , dan wordt de A en B met de X en de Y + stap afgetrokken, met als gevolg dat de sprite stil blijft + staan. + + HAPPEN + ++++++ + + Ook bij het HAPPEN van de witte blokjes, speelt het POINT- + commando de hoofdrol. Er wordt nl. iedere keer gekeken of + de sprite op kleur 15 staat (de kleur van de blokjes). Zo + ja, dan wordt er een zwart blokje overheen gezet, zodat het + lijkt alsof PACCIE het blokje heeft opgegeten. + + De volgende keer krijgt PACCIE zijn tegenstanders te zien. + + + + DEF FN , ON INTERVAL en INSTR + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Tot slot nog enkele handige BASIC commando's. + + DEF FNA (X,Y)= Met dit commando kunt U een + eigen vergelijking laten oplossen + Het bijbehorende commando waarmee U de vergelijking kunt + laten werken is + + A=FNA In A komt dan de uitgerekende waarden. Bv. + + 10 'Voorbeeld DEF FNA + 20 ' + 30 DEF FNA (X,Y) =(X*X)+Y + 40 FOR X=0 TO 4 + 50 A=FNA(X,1) : PRINT ,A; : NEXT X + 60 END + + Na F5 te hebben gedrukt zal er dit verschijnen : + + 1 2 5 10 17 + + Want 0*0+1 = 1 + 1*1+1 = 2 + 2*2+1 = 5 + 3*3+1 = 10 + 4*4+1 = 17 + + P.S. I.P.V de A in DEF FNA kunt u ook een andere variable + gebruiken als U meerdere vergelijkingen wilt + invoeren. + De A in .=FNA moet dan natuurlijk ook worden + vervangen. + + + + ON INTERVAL= GOSUB + + Dit commando springt om de ID interrupts naar . + Bij 1 interrupt (letterlijk onderbreeking) wordt om de 1/50 + of 1/60 seconde naar een bepaalt adres gesprongen. Staat hier + een z.g.n. RET dan gebeurt er niets, andersdan wordt naar de + gedefinieerde plaats (regelnummer) gesprongen. (zie ook de + ML cursus #7). + Bij dit commando horen nog 3 commando's nl. : + + INTERVAL ON : Het commando wordt in werking gebracht (na + iedere ID interrupts wordt er naar het regel- + nummer gesprongen.) + + INTERVAL OFF : Het commando ON INTERVAL wordt gestopt. + + INTERVAL STOP : Het commando ON INTERVAL wordt genegeerd. + Als U nu weer INTERVAL ON wordt gedaan dan + zal er verder worden gegaan waar is + genegeerd. + + Dit commando is zeer geschikt om een regelmatige klok op te + laten lopen , zie het voorbeeld hieronder : + + 10 'VB. van interval klokje + 20 ' + 30 TIJD=300 + 40 ON INTERVAL=60 GOSUB 80 + 50 INTERVAL ON + 60 A$=INKEY$ : IF A$<>CHR$(13) THEN 60 ELSE END + 70 'INTERVAL + 80 LOCATE 0,0 : PRINT TIJD : TIJD=TIJD-1 + 90 IF TIJD<0 THEN END ELSE RETURN + + + Tot slot nog het INSTR commando : + + A=INSTR(B,A$,B$) : In A komt te staan het hoeveelste + karakter van A$ gelijk is met het + eerste karakter van B$. Er wordt gezocht + vanaf plaats B. Als B niet wordt ingevuld + (A=INSTR(A$,B$)) dan wordt vanaf het + eerste karakter in A$ gezocht. + + Bijvoorbeeld : + + PRINT INSTR("ABCD","A") + 1 + + PRINT INSTR(2,"ABCD","A") + 0 + + PRINT INSTR("ABCD","E") + 0 + + 10 CLS : PRINT "WILT U EEN GETAL INVOEREN ? (J/N)" + 20 A$=INKEY$: IF INSTR("JjNn",A$)>0 THEN 30 ELSE 20 + 30 A=INT((INSTR("JjNn",A$)+1)/2) : IF A=1 THEN PRINT "JA" + 40 IF A=2 THEN PRINT "NEE" + 50 END + + Er wordt dus gekeken of A$ in "JjNn" zit. Zo ja , dan staat + geeft de INSTR : + als A$ = "J" ; 1 , A=INT((1+1)/2)=1 + als A$ = "j" ; 2 , A=INT((2+1)/2)=1 (INT(1.5)=1) + als A$ = "N" ; 3 , A=INT((3+1)/2)=2 + als A$ = "n" ; 4 , A=INT((4+1)/2)=2 (INT(2.5)=2) + + De toepassing van INSTR is vooral handig, als er heel veel + mogelijkheden zijn. M.b.v. ON (INSTR(A$,B$)) GOSUB, kan dan + naar de subroutines van iedere letter gegaan worden. + + + + + Dit was het weer voor deze keer. De volgende keer zoals + gezegd de laatste SPRITES en we gaan eens kijken hoe je de + computer kunt laten denken !!! + + De basic-files zijn ingepakt. Je kunt ze uitpakken met + het bekende programma PMEXT.com. Ga dus eerst naar MSX-Dos + en typ: PMEXT A:BASICC.PMA B:*.* + Pmext staat op deze FutureDisk! + + Tot de volgende keer . + + TOM WAUBEN + + P.S. Heeft U nog vragen over deze cursus of zit u gewoon met + een probleem over BASIC , bel dan gerust naar : + + 046-758100 (na 15.00 u.) + + P.P.S Lees ook de EXTRA SEB op deze disk. (deze gaat + over de VDP-registers). + + + + SPECIAL EFFECTS BASIC #4+ + ------------------------- + + EXTRA *** EXTRA *** EXTRA *** EXTRA *** EXTRA *** EXTRA + + + Jazeker !! Deze keer een EXTRA SEB, om eens wat meer + tegemoet te komen aan de wensen om BASIC wat algemener te + nemen, immers BASIC heeft veel meer mogelijkheden. Daarom + deze EXTRA rubriek. + + Deze keer worden een aantal VDP-registers uitgediepd, met + name de registers 13 en 14. + + + VDP ... + +++++++ + + In BASIC bestaan 1 commando om in de VDP te schrijven of te + lezen ,nl. + + VDP()= + + Hierbij is het registernummer en de aarde. Bij + deze VDP-registers worden altijd een aantal bits geset, om + de gewenste uitwerking te krijgen. + + De VDP (letterlijk Video Display Processor) bepaalt het + uiterlijk van het scherm. De registers hebben dus allemaal + (direct of indirect) invloed op het scherm. Hieronder ziet u + een lijst van de belangrijkste VDP-registers in SCREEN 0. + Alleen register 24 is voor screen 5 t/m 12. + Alle VDP-registers bespreken zou alleen maar langdradig + worden. + + + VDP(7) : Bevat de (1e) voorgrond en achtergrond kleur. + De eerste 4 bits bevatten de voorgrondkleur en de + laatste 4 de achtergrondkleur. + + Bijvoorbeeld : + + VDP(7)=&b00011111 '= COLOR 1,15 (&b0001=1,&b1111= + 15) + + + VDP(9) : De vierde bit van register 9 bepaalt of sprites wel + of niet afgebeeld worden op het scherm. Als deze + geset is, worden ze wel afgebeeld , anders niet. + + + VDP(10) : Hiermee kan de frequentie worden bepaald (50 of 60 + Hz.). Als bit 2 geset is dan is de frequentie 50 + Hz., anders 60 Hz. + + Bijvoorbeeld : + + VDP(10)=&b00000000 'dit is 60 Hz. + + VDP(10)=&b00000010 'en dit 50 Hz. + + + VDP(13) : Dit is ��n van de leukste VDP-registers, samen met + VDP(14). + Het bepaald de tweede voor- en achtergrond kleur + van het scherm. + + Bijvoorbeeld : + + VDP(13)=&b00101110 '2e voorgrond = 2 (&b0010) en + 2e achtergrond =14 (&b1110) + + + VDP(14) :Bepaald hoe lang voor- en achtergrond 1 en hoelang + voor- en achtergrond 2 te zien zijn. + + Deze 2e kleur in screen 0 is alleen te gebruiken + als BLOKKEN. Over iedere positie van het scherm + kan een blokje worden gezet. Voor ieder blokje + staat een bit in V-ram. Deze reeks bits lopen + van adres &h800 to &h905. + + Het is dus mogelijk om 4 kleuren in screen 0 te + krijgen. Dit is erg handig bij allerlei + toepassingen, zoals een menu-balkje (zie SEBMENU op + deze disk). + + Nog een handige functie bij VDP(14) is dat er zelf + bepaald kan worden hoe lang de 1e voor- en achter- + grond en hoe lang de 2e voor- en achtergrond wordt + laten zien. Er kan dus een knipper effect worden + gecre�rd. De eerste nibble (de eerste 4 bits) geeft + aan hoelang de 2e kleuren en de tweede nibble geeft + aan hoeland de 1e kleuren op het scherm staan. * + + Dus bij VDP(14)=&b11110000 zullen altijd de tweede + kleuren op het scherm staan. + + Leuk is dan het knipperen altijd blijft doorgaan, + ook onder het laden. (zie het programma EXTRA.BAS) + + + Bijvoorbeeld : + + 10 SCREEN 0 + 20 FOR I = &H800 TO &H905 : VPOKE I,0 : NEXTI 'WIS + ALLE BITS + 30 VPOKE &H800,&B1010101 + 40 VDP(13)=&HF4 'VOORGROND 15, ACHTERGROND 4 + 50 VDP(14)=&H55 'KNIPPER EVEN LANG 5x 2e KLEUREN, + 5x 1e KLEUREN + 60 GOTO 60 + + * Met "1e kleuren" worden bedoeld de standaard kleuren + Met "2e kleuren" worden de kleuren gezet met VDP(13) + bedoeld. + + + VDP(19) : Dit register is identiek aan SET ADJUST (X,Y). + De Y is bij dit register de eerste nibble, de X + de tweede. Het verschil met SET ADJUST is dat + VDP(19) niet (!) weggesaved wordt in de klokchip. + De ADJUST kan dus veranderd worden, zonder dat de + standaard instelling wordt "aangetast". + + Bijvoorbeeld : + + VDP(19)=&hF1 'komt overeen met : SET ADJUST(1,0) + + VDP(19)=&h27 'komt overeen met : SET ADJUST(-1,-7) + + + VDP(24) : Tenslotte register nummer 24. De werking van dit + register is het beste uit te leggen met een + voorbeeldje, nl. DD-graph. + Als er uit een optie wordt gekozen, scrollt het + hele beeld soepel naar onder. + Dit is ook de werking van VDP(24). Het laat het + beeld in zijn geheel verticaal scrollen. Ook + hiervan staat een leuk voorbeeld in dezelfde file + (EXTRA.BAS). + + Ook van de andere registers zijn voorbeelden. Al deze + voorbeelden staan in 1 file : EXTRA.BAS , op te starten in + het SEBMENU.LDR . + + In de volgende SEB EXTRA zal het toetsenbord met z'n + functies worden uitgediept. + + + TOM WAUBEN diff --git a/future_disk/075/turbo-r_basic.md b/future_disk/075/turbo-r_basic.md new file mode 100644 index 0000000..34ffa3b --- /dev/null +++ b/future_disk/075/turbo-r_basic.md @@ -0,0 +1,184 @@ +Turbo-R basic(1) + + +De tekst Turbo-R basic(2) is ooit al eens geplaatst op +FutureDisk #2 en hebben we herplaatst aangezien de +FutureDisk nu een stuk meer gelezen wordt en het wel bij dit +artikel past. + +In deze tekst ga ik wat dieper in op het commando +CALL PCMPLAY, dus als je dit al geen reet interesseert +dan kun je nu al op duwen. + +Voor wat basisinformatie verwijs ik even naar de andere +Turbo-R basic tekst op deze disk. + +We hebben in het verleden (en ook op deze FutureDisk) nog al +wat sample-liedjes voor de Turbo-R in het demo-menu gehad. + +Waarschijnlijk als je al eens geprobeerd hebt om een liedje +door de hoofdthema's(rode draad deuntjes door een muziekstuk +heen) te samplen en op je Turbo-R na te maken(house-liedjes +dienen zich hier het makkelijkst voor, aangezien deze muziek +heel simpel opgebouwd is;veel herhaling enz.). Heel vaak heb +je niet genoeg aan 64K(basic-tool memory) in het sample- +programma dat bij je Turbo-R zit(dat je trouwens het beste +kunt gebruiken voor samples) aangezien je dan meestal maar te +weinig gesampled krijgt. +Met 128K en dus 2 maal 64K lukt het meestal wel een +fatsoenlijk liedje te maken(kijk maar naar NO LIMIT op deze +disk!). Alleen is het dan een probleem hoe je dit gaat +afspelen in BASIC. Je kunt natuurlijk met de Ramdisk werken +(dus CALL Ramdisk), en daar je samples op zetten. Het +probleem wat je echter dan krijgt, is dat het net iets te +lang duurt voordat je ��n van de samples vanaf de Ramdisk +weer in het gewone RAM gezet krijgt. + +De oplossing is heel simpel! Zet gewoon je twee samples in +het VRAM, daar passen ze allebei net in. Hoe dat kan, zal ik +in het volgende voorbeeld programmaatje laten zien. + +10 SCREEN 5 +20 SET PAGE,0: BLOAD"SAMPLE1.PCP",S +30 SET PAGE,2: BLOAD"SAMPLE2.PCP",S +40 'ZET HIERNA JE AFSPEELROUTINE(S) + +In regel 10 roepen we screen 5 aan(4 pages) waarna we de +eerste sample van 64K op page 0 en 1 zetten en sample 2 op +de tweede en de derde. +Het afspelen van je sample(of delen van de sample) op +normale snelheid gaat dan als volgt: + +CALL PCMPLAY(@BEGINADRES,EINDADRES,1,S) + +,S staat er natuurlijk voor dat het VRAM afgespeeld +wordt en ,S moet je dus niet vergeten te typen. + +Voor beginadres en eindadres geldt echter wel altijd dat +beginadres>eindadres; achteruit afspelen gaat helaas niet. + +De tweede sample begint in ons geval ongeveer bij @65000. + +Tot zover het commando CALL PCMPLAY. Vanaf deze FutureDisk +is de Turbo-R basic corner dus weer tijdelijk terug(wegens +vele verzoeken). De volgende keer ga ik in op de +PCM-outpoorten, waarmee overigens in "NO LIMIT" al mee +geklooid wordt. +Veel plezier met samplen! + +Koen "ik kan ook nog wat anders dan uit men nek lullen" Dols + + +Turbo-R basic (4.0 en 4.1) +---------------------------- + +In deze tekst worden (bijna) alle bevelen die aan basic 2.0 toe- +gevoegd zijn uitgelegt. De MSX-2+ bevelen staan dus ook nog +uitgelegd. +Nadere informatie: In de A1ST zit basic versie 4.0 en in GT +basic 4.1. + +Bevel 1: +Set scroll(X,Y,A,B) + +Het getal dat we voor X invullen geeft aan hoeveel +pixels het beeldscherm horizontaal verplaatst/ver- +schoven wordt.Het beeld dat links verdwijnt komt hier- +bij natuurlijk op de rechterkant van het beeldscherm +weer terug.(De waarde van X kan 0 t/m 511 zijn). +Voor Y geldt hetzelfde principe alleen scrollt U het +beeld hierbij vertikaal(De waarde van Y kan 0 t/m 255 +zijn). +Met de A kan men de eerste en laatste 8 pixels +uitzetten waardoor een vervelend geflikker vermeden +wordt ( Voor A gelden de waarden 0 en 1, wel of niet). +Voor B kan men ook alleen de waarden 0 en 1 invullen +(met zelfde betekenis) en kan men bepalen of men de +pagina achter de afgebeelde pagina mee wil laten +scrollen. + +Bevel 2: +Call Kanji X + +Met dit bevel kan de Kanji mode aangezet worden,waar- +door de karakters veranderen. Voor X kan 0 t/m 3 inge- +vuld worden. Op elk scherm kan nu PRINT gebruikt +worden PRINT #1 heb je dus niet meer nodig. + +Bevel 3: +Call CLS + +Dit bevel heeft dezelfde functie als CLS maar +aangezien CLS niet in de Kanji mode(zie hierboven) +werkt moet men dan dus dit commando gebruiken. + +Bevel 4: +Call ANK + +Met dit bevel wordt de Kanji Mode uitgeschakeld als +deze 'aan' was. + +Bevel 5: +Put Kanji(X,Y),T,K + +Met dit bevel kan een bepaald Kanji-teken en/of een +ander karakter dat de computer kent op het beeldscherm +afgebeeld worden. De X en Y zijn de co�rdinaten op het +beeldscherm van het te plaatsen karakter. De T staat +voor het karakternummer en de K voor de kleur. + +Voorbeeldprogramma dat U alle karakters laat zien: + +10 SCREEN 7 +20 FOR A=8000 TO 30000 +30 PUT KANJI(50,100),A,13 +40 FOR I=1 TO 90:NEXT I +50 NEXT A +60 END + +Bevel 6: +SCREEN X + +Dit bevel is uitgebreider geworden men kan nu voor X +de getallen 0 t/m 12 invullen. Alleen Screen 9 bestaat +(nog) niet. + +Bevel 7: +CALL PALETTE=(K,R,G,B) + +Als de Kanji-mode 'aan' staat werkt het commando +Color=(K,R,G,B) niet meer. +De K staat voor het kleurnummer(0 t/m 15) en met de +waardes R(hoeveelheid rood ,0 t/m 7),G(hoeveelheid +groen,0 t/m 7) en B(hoeveelheid blauw,0 t/m 7) kan +deze oorspronkelijke kleur K verandert worden. + +Bevel 8: +MOTOR ON/OFF +De Turbo-R heeft geen kassette-recorder aansluiting +dus deze commando's komen te vervallen. + +Bevel 9: +CALL PCMREC(@BEGINADRES,EINDADRES,kwaliteit,vol.reactie,KB,S) +Voor het opnemen van een sample. +Als beginadres kan men 0-65535 in vullen evenals het +eindadres. Voor kwaliteit kan 0 t/m 3 ingevuld worden. +Volume-reactie houdt in dat de Turbo-R pas reageert +bij een bepaalde hardheid van de klank.Hiervoor kan +men 0 t/m 127 invullen.Voor KB moet men 1 invullen als +men iets geheugen wil sparen. De S kan ingevuld worden +als U wilt dat de sample in het video-geheugen opge- +slagen wordt. + +Bevel 10: +CALL PCMPLAY(@BEGINADRES,EINDADRES,kwaliteit) +Voor het afspelen van een eerder opgenomen sample. +Zie voor informatie bij CALL PCMPLAY + + +Hopelijk heeft deze tekst U wat meer geleerd over basic +3 en 4. Misschien op FutureDisk #3 een vervolg... + + + Koen Dols + diff --git a/future_disk/10/machinetaal_10.md b/future_disk/10/machinetaal_10.md new file mode 100644 index 0000000..efa7aae --- /dev/null +++ b/future_disk/10/machinetaal_10.md @@ -0,0 +1,273 @@ +---- MACHINETAAL CURSUS DEEL 10-1 ---- + + + + + + + + + + +Eindelijk heeft de nummering van de FutureDisk dan toch de +machinetaalcursus bijgehaald. Maar ja, wat wil je als de +hoofdredacteur compleet gestoord(NvdR. Komt dat misschien +niet door jou, dat ik zo gestoord ben, Jantje?) is en vanaf +nummer 6 steeds vreemdere nummeringen gaat hanteren. + +Genoeg gekanker... + +Daar we al bijna de complete instructie set van de Z80 hebben +behandeld is de machinetaalcursus eigenlijk dood en zou je +nu moeten kunnen programmeren in mcode. +Het leek ons nu interessant om meer achtergrond informatie +over de verschillende microchips in je MSX te geven. +Daarom beginnen we dan ook met de bespreking van de + +---- Programmable Sound Generator ---- + +De Programmable Sound Generator (kortweg PSG) is de +standaard MSX geluidschip. Deze kun je dan ook in iedere MSX +aantreffen. Het is een AY-3-8910 (of verwante) microchip en +wordt in het MSX-systeem gebruikt voor de BEEP en muzikale +ondersteuning. Ons peesgeetje kan de volgende dingen: + +* Via 3 toongeneratoren 4096 verschillende frequenties +weergeven op 16 volumeschalen. +* Met een Envelope generator kunnen instrumenten benaderd +worden. +* Met een Noise generator (Ruis!!!) kunnen drums, explosies +en golven gecre erd worden. + +Dit klinkt misschien allemaal spectaculair en je vraagt je +misschien af waarom al die PSG melodietjes zo "slecht" +klinken. +Het probleem is dat de PSG de envelope en noise generators +niet op meerdere kanalen kan toepassen. Je kunt maar 1 +kanaal op een viool doen lijken, een ander op een drum, maar +er blijft er 1 het monotone PSG geluid voortbrengen dat je +hoort als je in BASIC een PLAY opdracht geeft. +Toch mag je niet klagen. Bedenk dat deze chip (lang) voor +1983 ontwikkeld werd en toen zeer goed was (wel eens een +VIC20 horen dreunen??) en dat spellenmakers als Konami, +Compile, T&E soft en weet ik wie, er toch zeer goede muziek +uit voortbrachten. Muziek van de MicroCabin, die zowel PSG +als FM-Pac gebruikt, klinkt soms zelfs als MIDI muziek. + +Nu ongeveer de mogelijkheden van de PSG zijn opgesomt kunnen +we eens gaan kijken naar de meer programmatische kant (wat +een woord!!) oftewel HOE KRIJG IK D'R GELUID UIT ???? + +De communicatie tussen de Z80 en de PSG verloopt via de I/O +poorten #A0 t/m #A2. + +I/O poorten ??? Oke, bijna alles hadden we behandeld: + +Input/Output poorten zijn de verbindingen van de Z80 met z'n +hulpchips zoals de diskdrive, VDP, PSG etc. +Je kunt je dit het beste voorstellen als mannetjes die met +touwtjes aan elkaar zitten. Als het belangrijkste mannetje +(de Z80 dus) een ruk aan het touw geeft (een stroompje +stuurt) gaat het mannetje dat aan het touw vastzit aan de +hand van de sterkte van de ruk een handeling uitvoeren. + +De Z80 heeft 256 van deze touwtjes (0 t/m 255) en kan +daarmee de hele MSX naar z'n hand zetten (een soort +dictatortje dus)(NvdR. Zoiets als mij?). Niet alle poorten +zijn bezet, een aantal is nog gereserveerd voor toekomstige +uitbreidingen. + +Je kunt de I/O poorten aansturen met de volgende Z80 +instructies: + + ---- Output instructies ---- + + +OUT (n),A + +* Deze instructie stuurt de inhoud van A naar poort n. +n kan een waarde hebben van 0 tot 255. + +OUT (C),r + +* Deze instructie stuurt de inhoud van register r naar +de poort waarheen het C-register verwijst + +OTDR (OuTput Decrement Repeat) + +* Stuurt de inhoud van het adres waar HL naar verwijst +naar de poort waar register C heen verwijst. HL wordt +daarna met 1 verlaagd. Het register B, dat als teller +gebruikt wordt, wordt met 1 verminderd. Zolang B niet +nul is wordt de instructie herhaald. + +OTIR (OuTput Increment Repeat) + +* Doet hetzelfde als OTDR alleen wordt het HL register +nu verhoogd i.p.v. verlaagd. + +OUTD (OUTput Decrement) + +* Doet weer hetzelfde als OTDR alleen wordt de +instructie nu niet herhaald totdat B gelijk aan nul +is. Register B wordt gewoon verlaagd. + +OUTI (OUTput Increment) + +* Gelijk aan OUTD, alleen wordt HL verhoogd. + + + ---- Input instructies ---- + + +IN A,(n) + +* Omgekeerde van OUT (n),A. De Z80 vraagt nu een waarde +van het randapparaat. In register A komt nu de waarde +van de met n gespecificeerde poort. + +IN r,(C) + +* Register r wordt geladen met de waarde van de poort +waar register C naar verwijst. + +INDR (INput Decrement Repeat) + +* Tegenovergestelde van OTDR. + +INIR (INput Increment Repeat) + +* Tegenovergestelde van OTIR + +IND (INput Decrement) + +* Tegenovergestelde van OUTD + +INI (INput Increment) + +* Tegenovergestelde van OUTI + + +Gewapend met deze informatie zijn we klaar om de I/O poorten +voor de PSG te bestormen. +(Maar dat doen we in tekst 2) + +---- MACHINETAAL CURSUS DEEL 10-2 ---- + +(Ok�, maak de borst maar nat,we moeten de PSG bestormen!) + + + + + + + + + +In poort #A0 moet je het registernummer zetten dat je wilt +onderzoeken. Met poort #A2 kun je de inhoud vervolgens +lezen en met poort #A1 kun je de inhoud veranderen. + +Huh ?? Registers ?? De PSG ??? + +Ja, ook hulpchips kunnen registers hebben net zoals de Z80. +Een hulpchip is namelijk een eigen processor. De Z80 kan +alleen via een paar registers commando's geven aan een +hulpchip. Als je de PSG een toon wilt laten voort brengen +moet de Z80 eerst de commando's voor die toon doorsturen, +maar daarna neemt de PSG het over en blijft zo'n toon +klinken totdat het Z80 het commando voor "uit" geeft. + +In de volgende cursus zullen we dieper ingaan op de +registers van de PSG en hun functie. We sluiten dit keer af +met een explosie geluidje in machinetaal... luistert en +huivert. +;EXPLOSIE.GEN +;(C) Michiel Visser + + DB #FE ;Header voor GEN80 + DW ST,EN,ST ;Bij WBASS2 overbodig + + ORG #C000 + +ST: + XOR A ;a=0 + LD E,0 + CALL WRTPSG + LD A,1 + LD E,5 + CALL WRTPSG + LD A,2 + LD E,0 + CALL WRTPSG + LD A,3 + LD E,13 + CALL WRTPSG + LD A,4 + LD E,255 + CALL WRTPSG + LD A,5 + LD E,15 + CALL WRTPSG + LD A,6 + LD E,30 + CALL WRTPSG + LD A,7 + LD E,0 + CALL WRTPSG + LD A,8 + LD E,16 + CALL WRTPSG + LD A,9 + LD E,16 + CALL WRTPSG + LD A,10 + LD E,16 + CALL WRTPSG + LD A,11 + LD E,0 + CALL WRTPSG + LD A,12 + LD E,5 + CALL WRTPSG + LD A,13 + LD E,0 + CALL WRTPSG + + LD B,255 +WACHT: ;even wachten + PUSH BC + POP BC + DJNZ WACHT + + LD A,12 + LD E,56 + CALL WRTPSG + LD A,13 + LD E,0 +WRTPSG: + OUT (#A0),A ;Register + LD A,E + OUT (#A1),A ;Data Write !! + RET +EN: + END + +Misschien is het je al opgevallen dat de data veel +overeenkomst vertoont met de BASIC opdracht SOUND. In weze +doet SOUND niets anders dan het weg"outen" van de waardes +naar de PSG. Zo zie je maar hoe machinetaal georienteerd de +BASIC wel niet is !! + +Overigens is de routine WRTPSG rechtstreeks uit de BIOS +gehaald. We hebben ze even uitgetikt om het OUT commando te +verduidelijken. + + Rest ons nog de ASCII en Michiel Visser te + bedanken voor hun medewerking. + + Veel programmeerplezier van: + + Jan Willem van Helden + en Ruud Gelissen + diff --git a/future_disk/10/special_effects_basic_5.md b/future_disk/10/special_effects_basic_5.md new file mode 100644 index 0000000..eb4d209 --- /dev/null +++ b/future_disk/10/special_effects_basic_5.md @@ -0,0 +1,174 @@ + SPECIAL EFFECTS BASIC 5 ??? + --------------------------- + + Helaas , maar deze keer geen SEB...... Dit zou een dubbel + jubileum moeten worden (FD 10 en SEB 5) maar ik heb geen + tijd gehad om de nodige voorbeelden te schrijven en me te + verdiepen in het hoe en wat om de computer te laten + "denken" (dit zou dus het onderwerp zijn.) en VECTOR MANIA + (zie elders) nam (en neemt) veel tijd in beslag. + + Maar niet getreurd!!(NvdR. Nee, natuurlijk niet!!) Op deze + disk staat de goede versie van de SEB manual. Hoe u deze + ingepakte file moet uitpakken ziet u in de file "SEBPATCH.LDR" + die u kunt laden vanuit het software menu. + + De volgende keer dus een (lange) SEB over het denken van de + computer en om deze tekst toch niet heel afgezaagd te maken + is hieronder toch nog een (mini) SEBje .... + + + SEB vier drievierde + ------------------- + + Deze keer alleen de behandeling van de twee moeilijkste + diskbasic commando's : + + DSKI$ en DSKO$ + + en de RAMdisk van de MSX wordt eens besproken. + + + DSKI$ + ----- + Dit is een afkorting van DISK INPUT (STRING). Met dit + commando kan er informatie van een disk worden gelezen. De + gehele syntax is : + + A$=DISK$(A,B) A is het nummer van de drive en B is het + sectornummer. Ik ga nu niet verder in op de + indeling van sectors, tracks etc. Kijk eens in + een MCCM, daar staan vaak teksten over de + opbouw van een disk. B moet positief zijn en + mag niet groter dan 1440 worden voor + gewone 80 tracks diskette. Voor een harddisk + kan dit getal varieren van 0 to 65535. Om A + uit te "rekenen" kan de volgende regel worden + ingetypt : + + PRINT ASC("A:")-64 'VUL VOOR A: DE DRIVE IN + 1 + + Als u dus van drive B: wilt lezen moet A 2 zijn. + + De informatie van de gewenste SECTOR staat NIET (!) in A$, + maar wordt opgeslagen in het RAM. Om deze te lezen moet u + het volgende programma in typen : + + 10 A$=DSKI$(1,0)'DRIVE A SECTOR 0 + 20 A=PEEK(&HF351)+256*PEEK(&HF352) 'HIER STAAT HET ADRES VAN + DE BEGINPLAATS VAN DE GELEZEN DATA + 30 FOR I=0 TO 100 '100 KARAKTERS ZOEKEN, DIT KAN VERANDERD + WORDEN. + 40 PRINT CHR$(PEEK(A+I)); : NEXT I 'LAAT HET KARAKTER ZIEN + WAT OP DE DISK OOK STAAT. + 50 END + + U ziet dat dit erg omslachtig is, maar in A$ zou het niet + passen, omdat in een string nu eenmaal maar 255 karakters + kunnen en in een sector 512. + + DSKO$ + ----- + + Om op een disk iets rechtstreeks te schrijven is er het + commando DSKO$. Dit is precies hetzelfde als DSKI$. Maar de + syntax is nu : + + DSKO$(A,B) Waarbij A en B hetzelfde betekenen als bij + DSKI$. Dit commando schrijft de informatie van + dezelfde adressen waar bij DSKI$ van werd + gelezen naar disk. + Als u deze informatie veranderd, kunt u dus ook + zelf iets op de sectors schrijven. + + In het onderstaande voorbeeldje wordt de naam van deze cursus + op sector 20 van drive B: geschreven. (LET OP , in sector 0- + 17 staat informatie van de disk. Gebruik bij experimenteren + een lege disk, anders zou het wel eens verkeerd met bv. de + FAT kunnen aflopen !) + + 10 A$="SPECIAL EFFECTS BASIC NUMMER VIER DRIE VIERDE" + 20 A=PEEK(&HF351)+256*PEEK(&HF352) + 30 FOR I=1 TO LEN(A$) 'POKE A$ OP ADRES A EN VOLGENDE + 40 POKE A+(I-1),ASC(MID$(A$,I,1)) + 50 NEXT I + 60 DSKO$(2,20) 'SCHRIJF OP SECTOR 20 VAN DRIVE B + 70 END + + Als u nu het vorige programmaatje aanpast om van drive B op + de 20e sector te lezen (A$=DSKI$(2,20)) dan zult u zien dat + er de tekst van regel 10 in de 2e listing verschijnt. + Experimenteer gerust , maar wel met een lege disk !!! + (Wij zijn niet aansprakelijk voor de gevolgen, van onkundig + gebruik!) + + RAMDISK + ------- + + Jazeker , ook u MSX 2 heeft een RAMDISK ! Maar helaas is + deze niet zo uitgebreid als bv. de RAMDISK (H:) van de + Dos-2 Cartridge. + Er zijn een aantal commando's speciaal voor de RAMDISK, maar + er zijn ook veel gebreken. Op het laatste komen we later nog + even terug. + + CALL MEMINI Dit "maakt" de RAMDISK aan. Als het goed is + veschijnt er als u RETURN drukt : + + 32000 bytes allocated + + U ziet dat deze RAMDISK 32000 bytes (zo'n 31 KB.) vrij + maakt. Hierop kunt u laden en saven door simpel i.p.v. het + disknummer MEM: te typen. Als u bv. de file NAAM.EXT op de + RAMDISK wilt saven typt u : + + SAVE"MEM:NAAM.EXT" + + Dit is precies hetzelfde met laden. Maar als u de + inhoudsopgave wilt zien, dan gaat dit NIET met + FILES"MEM:*.*" !!! Daarvoor is een appart commando evenals + KILL en NAME : + + CALL MFILES Laat u de inhoudsopgave van de RAMDISK zien + CALL MKILL("") Verwijderd een bestand van de RAMDISK + CALL MNAME(""as"") NAMED een bestand van de + RAMDISK. + + LET OP DE HAAKJES BIJ CALL MKILL EN CALL MNAME !!!!!!!!!!!! + + Dit zijn alle commando's die er zijn. Om tijdelijk BASIC + programma's te saven is dit een goede oplossing maar na een + RESET is alles weg !!!!!! + + Toch is het niet allemaal rozegeur en maneschijn wat deze + RAMDISK betrefd. Als we een ML file willen laden of saven + dan gaat dit niet om de simpele reden dat je geen MEM: kunt + typen bij het BLOAD-en BSAVE commando (er verschijnt + dan een foutmelding). + + Maar nog een groter nadeel is het ontbreken van MEM: bij + het COPY commando. Door deze twee gebreken is het dus + onmogelijk om bv. grafische files te laden en saven en er + kunnen ook geen files effe gecopi erd worden. Daardoor wordt + deze RAMDISK niet vaak gebruikt en daarom wordt er ook niet + vaak over gesproken. Maar voor de basicprogrammeur is deze + RAMDISK toch wel handig. SAVEN en LADEN gaat immers wel en + ook het MERGE commando ondersteund deze interne disk. (NvdR. + Saven en Laden, gaat wel verschrikkekekeklijk langzaam!) + + Let er wel op dat er altijd in het begin CALL MEMINI moet + worden gedaan !! + + P.S. I.p.v. CALL kan ook het kortere _ (laag streepje , + +<->) worden gebruikt. + + + Dit was het weer voor deze keer. De volgende keer zoals + beloofd de echte SEB 5 met veel voorbeelden. Bij deze SEB + zijn geen voorbeelden (ook niet echt nodig, geloof ik)(NvdR: + geloven doe je in de kerk, Tom!) + + Tot de volgende keer , + + TOM WAUBEN diff --git a/future_disk/11/machinetaal_11.md b/future_disk/11/machinetaal_11.md new file mode 100644 index 0000000..62b0d8b --- /dev/null +++ b/future_disk/11/machinetaal_11.md @@ -0,0 +1,128 @@ +���� Welkom bij het 11de deel van ���� +���� ���� +���� de MACHINETAALCURSUS ���� +���� ���� + + ------------------------------------------------------ + + Vorige keer hebben we o.a. de OUT/IN instructies behandeld en + beloofden we al om in dit deel uitvoerig op de PSG registers + in te gaan. + Misschien lijkt dat overbodig, omdat de gevorderde BASIC pro- + grammeur dit waarschijnlijk al lang beheerst, maar in + machinetaal is het allemaal veel beter uit te leggen. + BASIC is op het punt van de SOUND intructies namelijk erg + machinetaal geori�nteerd.(dus zonder het te weten zat je ook + vroeger al, je MSX bijna rechtstreeks te besturen d.m.v. + SOUND). + + De PSG registers. + + De PSG (Programmeble Sound Generator) kent 16 verschillende + registers, waarvan de eerste 14 dienen voor het genereren van + geluid. + + R0 en R1 dienen om de frequentie (lees:toonhoogte) te bepalen + van het eerste kanaal. Een frequentie kan bestaan uit 12 Bits + en dus varieren tussen de 0 en 4095 (2 tot de 12de-1). + De onderste 8 bits van deze frequentie moeten in register 0, + de bovenste 4 bits in register 1 gezet worden. + + Dat kan gebeuren met de volgende instructies: + + WRTPSG: EQU #93 ; BIOS + + XOR A ; A=0, weet je nog? + LD E,%xxxxxxxx ; Laagste deel freq. + CALL WRTPSG + LD A,1 ; register 1 + LD E,%xxxx ; Hoogste deel freq. + CALL WRTPSG + + R1 en R2 moet je gebruiken om de frequentie van kanaal B + te veranderen. R3 en R4 zijn dan natuurlijk voor kanaal C. + + Met de registers 2, 4 en 6 wordt dus de grove toon "geset", + met de registers 0,1 en 3 de fijne frequentieverschillen. + + Maar hoe speel ik nu een C op octaaf 4? + Daarvoor kun je het beste de volgende tabel gebruiken: + + 1 2 3 4 5 6 7 8 OCTAAF + ----------------------------------------------- + C - D5D 6AF 357 1AC D6 6B 35 1B + C# - C9C 64E 327 194 CA 65 32 19 + D - BE7 5F4 2FA 17D BE 5F 30 18 + D# - B3C 59E 2CF 168 B4 5A 2D 16 + E - A9B 54E 2A7 153 AA 55 2A 15 + F - A02 501 281 140 A0 50 28 14 + F# - 973 4BA 25D 12E 97 4C 26 13 + G - 8EB 476 23B 11D 8F 47 24 12 + G# - 86B 436 21B 10D 87 43 22 11 + A - 7F2 3F9 1FD FE 7F 40 20 10 + A# - 780 3C0 1E0 F0 78 3C 1E F + B - 714 38A 1C5 E5 71 39 1C E + ------------------------------------------------ + NOOT + + Voor een C op octaaf 4 zet je dus in register 0: &H0AC + en in register 1: &H001 + + Nu we een frequentie kunnen bepalen is het ten eerste van + belang dat de toon een volume toegewezen krijgt, hiervoor + dienen de registers R8 t/m R10. + Slechts de 5 onderste bits zijn van belang. + + Als de 5de bit (=&b000x0000) 0 is, geven de 4 onderste bits + het volume aan, dat daarmee kan varieren tussen 0 en 15. + Is de 5de bit 1 dan worden alle andere bits verwaarloosd en + wordt het volume bepaald door de zogenaamde Envelope Cycle. + + + De Envelope Cycle. + + Met behulp hiervan kan men een toon een bepaald + "aanzwel- en uitsterfpatroon" meegeven. + + In R13 wordt bepaald hoe dit patroon eruit ziet. Daarbij zijn + alleen de onderste 4 bits van belang. + + Men onderscheidt: + + 0-3: uitstervende toon (volume daalt) + 4-7: aanzwellende toon (volume stijgt) + 8 : uitstervende toon, die als hij helemaal weg is weer + opnieuw start (zaagtand vorm) + 9 : idem 0-3 + 10 : respectievelijk uitstervende- en aanzwellende toon + (na volume 15 gaat het volume dalen tot 0 en weer tot 15 + aanzwellen) + 11 : toon sterft uit en gaat daarna op maximum volume. + 12 : aanzwellende toon, die als hij helemaal hard is weer + opnieuw start (zaagtand vorm) + 13 : zwelt aan tot maximum en blijft zo hard. + 14 : idem 10, maar start met aanzwellen i.p.v. met uitsterven. + 15 : idem 4-7 + + Als we een patroon hebben gekozen, kunnen we ook nog bepalen + hoe lang de "aanzwel/uitsterfgolf" duurt m.b.v R11 en R12. + + Alle 16 bits mogen gebruikt worden; hoe hoger het 16 bits + getal hoe langer de golf duurt. + De laagste byte moet je in R11 zetten en de hoogste byte in + R12. Ook hier geldt dus: R12 regelt de grove- ,R11 de fijne + afstelling.. + + Onthoudt goed dat het vullen van de registers R11 t/m R13 + geen nut heeft als in een van de volume registers + (R8 t/m R10) geen 5de bit geset is.(16-31 staat.) + + Voor alle kanalen wordt dezelfde ENVELOPE gebruikt !! + + + Op de PSG kun je niet alleen tonen genereren, ook het maken + van ruis is mogelijk. + In de 5 laagste bits van R6 wordt de ruisfrequentie weer- + gegeven. Deze kan dus varieren tussen 0 en 31, waarbij 31 de + hoogste "ruistoon" is. De ruisfrequentie wordt normaal + gesproken aan alle 3 de kanalen meegegeven. M.b.v. register 7 diff --git a/future_disk/11/pascal_1.md b/future_disk/11/pascal_1.md new file mode 100644 index 0000000..66abe3f --- /dev/null +++ b/future_disk/11/pascal_1.md @@ -0,0 +1,51 @@ + Pascal (1) + ========== + +Men heeft mij gevraagd om een cursus PASCAL te schrijven. En +omdat ik PASCAL een goede, gestructureerde en leuke taal vind, +heb ik ja gezegt. + +Voordat ik ga beginnen met het echte werk, geef ik eerst een +korte inleiding over wat PASCAL precies inhoud. PASCAL is +vernoemd naar de wiskundige Blaise Pascal die van 1623 tot 1662 +leefde. Blaise Pascal was een van de grootste wiskundige die de +wereld gekent heeft. Hij heeft onder andere de fundamenten +gelegd van het kansrekenen. Maar het bekenste wat Blaise Pascal +heeft gedaan (buiten zijn bekende driehoek) is het constru�ren +van een rekenmachine. Deze machine kon veel rekenkundige +berekeningen uitvoeren, en dat terwijl het geheel alleen maar +uit tandwielen en dergelijke bestond (probeer je dat eens voor +te stellen). + +Rond 1970 dook de naam PASCAL (geheel in hoofdletters) weer op. +Dit omdat ene Professor Niklaus Wirth het leuk vond om zijn +zojuist ontwikkelde programeertaal te vernoemen naar Blaise +Pascal. En deze taal is nu h��l bekend. De meeste mensen hebben +er ervaring mee, of hebben er wel van gehoord. Het voordeel van +PASCAL boven BASIC is de gestructureerdheid. Is het verplicht +bij BASIC om commentaar te plaatsen (zeker als iemand anders er +iets van moet begrijpen) bij PASCAL word de helft van de +'documentatie' door de gestructureerdheid van de taal zelf +verzorgd. Hiermee bedoel ik dat je er bij BASIC een spagetie van +kunt maken (met behulp van GOTO-instructies) die niet te lezen +is. Terwijl je bij PASCAL het programma veel sneller doorziet +door het inspringen (word later duidelijk), de grotere +verscheidenheid aan herhalingslussen (WHILE, REPEAT en FOR) en +het (bijna) niet voorkomen van GOTO-instructies. + +Tot zover de inleiding. Nu gaan we dus echt beginnen. Dat echt +beginnen houdt in dat ik de globale structuur van een +PASCAL-programma ga uitleggen. + +De globale structuur van een PASCAL-programma is als volgt : + +PROGRAM programma_naam (INPUT,OUTPUT); + + CONST + {Constante definitie} + + TYPE + {Type definitie} + + VAR + {Variabelen declaratie} diff --git a/future_disk/12/pascal_2.md b/future_disk/12/pascal_2.md new file mode 100644 index 0000000..112ae14 --- /dev/null +++ b/future_disk/12/pascal_2.md @@ -0,0 +1,158 @@ + Pascal Cursus (2) + ================= + + + Wat is die Koen toch een etter. Nauwelijks ben ik een PASCAL + cursus begonnen of hij begint al met klagen. Vorige keer had + ik een leuke programmaatje op de disk laten zetten om je CD's + beter op te kunnen nemen, maar nee, voor meneer Dols is het + weer niet goed. + + Koen : Kan ik niet aangeven dat ik een 60 bandje heb? + Jeroen : Nee Koen, dat kan niet, dat was wat veel werk. + Koen : Wat is dat dan voor een stom programma, zorg er maar + voor dat dat volgende keer verbeterd is! + + Tja, en ik als goede onderdaan (Sahib, sahib) heb dat dus ook + maar gedaan. Ik hoop dus maar dat hij dit keer niets te zeiken + heeft.(NvdR: ik heb thuis ook nog 100 minuten bandjes + Jeroen!) + + Maar genoeg over onze sadist Koen. Nu gaan we over naar het + echte werk : programmeren. Als ik mij goed kan herineren, dan + hebben we het vorige keer over de globale structuur van PASCAL + gehad. Nu gaan we het over variabelen hebben. + + Een groot verschil tussen BASIC en PASCAL is dat het in PASCAL + verplicht is om alle variabelen die je gebruikt van te voren + aan te melden en te specificeren. Wat ik hiermee bedoel is dat + je de compiler duidelijk maakt hoe je variabelen heten (jan, + piet of klaas) en wat voor variabelen het zijn. Een variabele + declaratie zou er als volgt kunnen uitzien (de variabele + declaratie moet altijd vooraf gegaan worden door het + gereserveerde woord VAR) : + + VAR + teller : integer; + getal : real; + status : boolean; + + De opbouw van deze declaratie mag wel duidelijk zijn. Eerst + komt er het gereserveerde woord VAR. Op de volgende regels + volgt de naam van de variabele die je gaat gebruiken gevolgd + door een dubbele punt en het type van de variabele. Aan de + naam van de variabele is eigenlijk maar een grote restrictie, + de naam mag geen gereserveerd woord (zoals BEGIN, END, VAR, + etc) zijn. De dubbele punt is verplicht. Het type van de + variabele kan vanalles zijn, maar ik beperk me hier tot de + standaard types : + + - boolean (kan de waarde TRUE of FALSE hebben) + - byte (spreekt voor zich) + - integer (16 bits geheel getal, ook word) + - longint (32 bits geheel getal, ook longword) + - real (een gebroken getal, lengte hangt af van de machine) + - char (een ascii karakter) + - string (een reeks ascii karakters) + - text (een file met ascii karakters) + + De punt-comma op het einde van de regel is verplicht (bijna + alle programma regels in PASCAL worden afgesloten met een + punt-comma). Naast bovengenoemde standaard types kun je ook + zelf types ontwikkelen (dagen van de week bijvoorbeeld), maar + daar kom ik later op terug. Voor ik het vergeet, de laatste 2 + types zouden wel eens niet kunnen werken, daar ze niet vanaf + de eerste PASCAL versies ge�mplementeerd waren. Vanaf versie 3 + of hoger zouden ze echter aanwezig moeten zijn. + + Dan komen we nu bij de toewijzingen. Deze zijn zeer + gemakkelijk : + + getal:=2; + letter:='A'; + teller:=teller+1; + + Bovenstaande voorbeelden zijn erg simpel, maar geven het + principe goed weer. Een toewijzing wordt als volgt opgebouwd: + + Als eerste komt de variabele waar iets aan toegekend moet + worden. Dan volgt een dubbele punt met een "is-gelijk" + teken (spreek := uit als 'wordt'). En als laatste volgt de + waarde die de variabele moet krijgen. Deze waarde wordt + samengesteld zoals in BASIC, met een kleine restrictie: het + type mag (uiteraard) niet wijzigen. Dus als getal eerst een + integer was, dan mag deze niet door 'getal:=1.5' veranderd + worden in een real. Genoemde toewijzing zal resulteren in + een compiler fout of een run time error. + + Naast de gebruikelijke operators (+, -, *, (), AND, OR, XOR, + NOT) zijn er ook nog functies zoals CHR, ORD, ROUND, TRUNC, + ABS, ARCTAN, COS, EXP, FRAC, INT, LN, SIN, SQR, SQRT, etc. De + meeste namen duiden op soortgelijke functies uit BASIC, voor + meer details verwijs ik naar boeken over PASCAL. Genoemde + functies kunnen gewoon gebruikt worden in een toewijzing, als + men er maar aan denkt dat het type van de hele toewijzing + gelijk moet zijn aan het type van de variabele. + + Laatstgenoemde punt impliceerd dat er twee functies moeten + zijn om een getal te delen. Waarom? Omdat delen per definitie + een gebroken getal opleverd en dat dus niet een integer is. + Gehele getallen kunnen echter wel op elkaar gedeeld worden en + daarom is er een speciale functie nodig om integers te delen. + Deze speciale functie is de DIV functie (DIVide). De logisch + bijbehorende functie is MOD (MOD geeft de rest van de deling). + + Zo, dat was het voor deze keer. Maar voor ik jullie weer + verlaat (ooohh) geef ik jullie nog een voorbeeldje en een + opgave om zelf te maken. Van het voorbeeld programmaatje ga ik + niet veel verklappen, bekijk het maar eens en probeer (voor- + dat je het laat uitvoeren) te beredeneren wat het doet. Het + voorbeeld programmaatje staat op de disk onder PASCAL2.PAS (dan + hoeven jullie het niet over te tikken). + + De opgave daar wil ik iets anders mee doen. Als iemand zo gek + is om het te proberen, het op te lossen en de oplossing op te + sturen, dan beloof ik die persoon dat zijn oplossing volgende + keer geplaatst wordt. En om het nog aantrekkelijker te maken + vermelden we de naam van de persoon die de oplossing heeft + ingestuurd (H� Koen, wedje dat nu niemand meer iets instuurt. + Kun je tenminste niet weer kankeren dat je niet alles op de + disk kunt plaatsen wegens plaatsgebrek). + + Zo, genoeg getypt, nu de opgave : + Schrijf een programma dat om 3 netto prijzen van artikelen + vraagt. Bereken aan de hand van die prijzen : De BTW per + artikel, het totaal betaalde BTW bedrag, de totale BRUTO en + NETTO prijs van de drie artikelen. + + Aangezien ik nog niets heb gezegd over in- en uitvoer van + variabelen via toetsenbord en beeldscherm, verwijs ik naar het + voorbeeld programma. Door dit goed te bekijken moet het + mogelijk zijn om iets soortgelijks te construeren. + + Veel plezier en tot volgende keer, + + Jeroen 'KUBIE' Smael + Galopiahof 6 + 6215TK Maastricht + Tel : 043-437778 + + P.S. (1) Om een nieuwe programmeertaal te leren moet je zelf + een heleboel oefenen en uitzoeken, daar leer je + tenslotte het meeste van. Daarom kauw ik niet alles + voor, maar laat een heleboel aan jezelf over. + (2) Boeken die je kunt raadplegen zijn onder de VELE + andere : K.L. Boon / PASCAL voor iedereen / Kluwer / + ISBN 90.201.1425.5 --- Findley / PASCAL Inleiding tot + gestructureerd programmeren / Kluwer / ISBN + 90.201.1991.5 + (3) Let ook op de programmeerstijl die ik in het + voorbeeldprogramma gebruik. Er is geen standaard + voor, maar mijn stijl is wel gestructureerd en dat + bevorderd de leesbaarheid. + (4) Dankzij Koen staat er dus ook een verbeterde versie + van het CD programma op de disk (CD2.PAS / CD2.COM). + Veel plezier daarmee (nog iets te mekkeren, Koen?). + (NvdR: Ja, Jeroen: Bl���������������������������h!) + + C YA @ !! diff --git a/future_disk/12/special_effects_basic_5.md b/future_disk/12/special_effects_basic_5.md new file mode 100644 index 0000000..ae4062f --- /dev/null +++ b/future_disk/12/special_effects_basic_5.md @@ -0,0 +1,205 @@ + + �W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W� +W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W + SPECIAL EFFECTS BASIC #5 + �W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W� +W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W + + ���� + ���� + ���� + ���� + + + Na een keer te hebben overgeslagen is er dit keer dan toch + de SEB nummer 5 !!! Door de aloude reden "Ik had effe geen + tijd" heeft de SEB anderhalve editie FutureDisk moeten + overslaan. Maar dit keer is het de vijfde Special Effects en + dat moet gevierd worden !!! + + + LEES VERDER EN HUIVER !!!! + + Op een doordeweekse dag , helemaal uitgeput van 7 uur + schoolslapen moest ik toch maar eens naar de bibliotheek. + Ik moest nog 5 boeken lezen op 2 weken tijd (computer ik te + veel?!). Na alle leuke (????) boekenlijstboekjes te hebben + uitgezocht en de samenvattingsboeken gecopi�erd zag ik mijn + kans om eens te kijken of er nog wat MSX in de rekken, of + liever gezegd, in de computer stond. Al brakend liep ik naar + zo'n gore helemaal-onder-de-nicotineaanslag-zittende PC + (kots,kots) om daar nog na kokhalzend met bibberende vingers + M S X in te tijpen. Na veel geratel en een minuut wachten + (jaa, een PC uit '74) zag ik een aantal boeken verschijnen + maar omdat er na een uur bleek dat er geen in de bibliotheek + aanwezig was dook ik de rekken zelf maar in.... Na veel + zoeken tussen de stoffige Norton Utilities deel 1 tot en met + 100, zag ik een boekje met het opschrift MSX BASIC. + Heel erg blij slaakte ik een paar vreugdekreten, toen + ik me realiseerde dat ik naast de studiezaal stond. Na dat + k*twijf van me af te hebben gegooid en in de hoek gepleurd + zag ik kans om het boekje te pakken en het mee te nemen naar + een stil hoekje. Nadat ik alle drugsspuiten had opgeruimd en + een krant vond om wat van dat rode spul mee af te dekken + (bloed of zo??!) sloeg ik de eerste bladzijde open. 02 1985, + een oud boekje dus, maar toch verder. Na twee lijsten met + verbeteringen te hebben doorgelezen kom ik eindelijk aan bij + de inhoud. De normale zaken worden besproken zoals : hoe zit + een computer in elkaar, wat is MSX, heb je een toetsenbord + bij je MSX?, etc. De volgende bladzijde krijg ik met moeite + opengereten. Daar ligt een zielig muggenkerkhof, de barbaar + die het boek voor mij had, zal wel geen vliegenmepper hebben + gehad .... + Na te hebben gelezen dat MSX een geweldige toekomst tegemoet + zou gaan (ach ja , 1985) en dat iedereen (!!) een MSX zou + gaan kopen , kom ik aan bij het hoofdstuk "PRINT". Hier + wordt het print commando besproken, maar aangezien ik dit + toch al wist, ging ik maar meteen naar APPENDIX P. + In APPENDIX P stonden een aantal leuke korte programmaatjes + die ik U niet wil onthouden dus kijk maar es in 't software- + menu. LET WEL !!! De programma's zijn niet door mij + geschreven maar door de "AUTEUR" van dit boek. Kijk en be- + oordeel zelf .... + Het valt me op dat het octale stelsel uitgebreid besproken + wordt en dat iedere lezer geacht wordt al enige kennis met + binaire getallen te hebben, terwijl het boek (ik citeer) + "Voor velen een eerste kennismaking zal zijn, een kennis- + making waarbij de lezer stellig begrip hoopt te ontmoeten + voor de drempels die hij moet nemen. Voor deze lezers is + dit boek geschreven". + DEBIELE MONGOLE OERSTOMME ACHTERLIJKE IDIOTE OETLUL !!!!!!!! + Na het boek weer inelkaar te hebben geplakt bladerde ik er + nog eens doorheen. Haaa , een "Intermezzo, Kunnen computers + denken??". Verheugd lees ik verder ... om na 3 regels weer + te stoppen ; wat interesseert mij of de mensen 100 jaar + geleden wilden dat er een electronisch brein kwam! + Het boek was nu twee keer zo dik geworden omdat ik 't per + ongeluk buiten in de regen had laten liggen en daarna in de + afwasmachine had gestopt. Ik sloeg het open en zie bij + appendix Z een lijst van alle (!) basiccommando's. Dit staat + tenminste in de inleiding. Zou deze ****schrijver niets eens + van de commando's MKI$,MKD$ etc. hebben gehoord?? En waar + is het gedeelte over het laden en saven van disk. 1985?? + Kom nou, voorin het boek staat beschreven dat er "een + kastje met electronische schijfjes bij de computer kunnen + zitten. Computerproffesionals noemen dit een DISKDRIVE" + NEEEEEEEEEEEEEEE TOCH ?!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + Nadat ik geergerd de lijst met foutmeldingen doorlees (ach + ja, tijd te veel ?!) denkend dat hier niets fout kan gaan + (handleiding overschrijven) zie ik dat er een illegal + fuction call wordt gegeven als : 1) negatieve arrayindex, + 2) SQR(-1) / LOG(-1), 3) verkeerd gebruik USR, MID$,etc. + En als ik dan SCREEN 900 intyp ?? ILLEGAL FUCTION CALL. + Met in het achterhoofd dat het boek uit 1985 komt (waarom + lees ik deze crap??) kan ik me er nog net van weerhouden + het boek (wat daar nog van over is) te begraven... + + Omdat we geen WC-papier hadden en ik het boek toch niet + meer las konden we iedere bladzijde gebruiken als + WC-blaadje. Alleen de kaft was nogal hard ...... + De kaft heb ik daarna maar lekker baldadig op de stoep + gelegd , een kan benzine gehaald en 't daarin gedompeld en , + ach ja de rest weet U wel! + De bibliotheekaaresse (??????) vroeg niet eens waar het boek + was (of had ik het meegenomen zonder te laten afstempelen?!) + Weer thuis gekomen wist ik eindelijk waar deze SEB over zou + gaan : KUNNEN COMPUTERS DENKEN ?? + + Nou om maar te eindigen met dit (ingekorte) EEN-DAG-UIT-HET- + LEVEN-VAN-EEN-RANDIMBICIEL verhaal, hieronder een verhaaltje + hoe computers kunnen "denken". + + *************** DENK-COMPUTER ????! **************** + + Een computer moet worden gezien als een kastje met enkele + electronische schakelingen en chips die bewerkingen kunnen + uitvoeren. + EEN COMPUTER KAN DUS NOOIT DENKEN + + Maar omdat we de kennis (??!) hebben om een programma te + schrijven kunnen we ons DENKPATROON in de computer invoeren. + Het gaat dus om PATROONHERKENNING en niets anders. Dit + patroon moet worden uitgezocht dus enige voorstudie is nood- + zakelijk. Als je wilt dat de computer een spel kan spelen met + "strategie" dan zal de programmeur een stappenplan moeten + maken waarin staat wat de computer precies moet doen om zo + te winnen. + + Bij het onderstaande programmaatje is dit patroon wel duidelijk + : + 13 lucifers, de som van de weggepakte lucifers moet 4 zijn + want als dit zo is dan blijven er achtereenvolgens 13,9,5,1 + lucifer(s) over. Wie de laatste lucifer over houdt heeft + verloren. + + De computer wint altijd !!. Speel het maar eens ; U zult + zien dat U altijd verliest (LUCIFER.LDR) + �W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W� +W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W + + Kort samengevat : + + 1) Bestudeer spel + strategie + 2) Maak stappenplan (PATROON) + 3) Laat de computer het PATROON HERKENNEN (vertaal 2 in een + programma) + + �W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W� +W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W�W + + Als tweede voorbeeld nemen we een veel moeilijker patroon + nl. dat van BOTER-KAAS EN EIEREN (TIC-TAC-TOE) + + SPELREGELS : + + Er wordt gespeeld in een matrix van 3x3. Het doel is om zo + snel mogelijk drie op een rechte lijn te krijgen. Er mag + niet over een anders heen gezet worden en er zijn 2 spelers + die om de beurt spelen. + Allereerst moet de computer de spelregels kennen. We maken + eerst een versie die alleen de spelregels kent. Het is + altijd goed eerst zo'n "stomme" versie te maken die werkt + omdat de patroonherkenning nogal ingewikkeld is. + We maken eerst alles in screen 0 om het daarna over te + plaatsen in bv. screen 5. Dit is niet zo moeilijk als de + "screen 0 versie" werkt. Bekijk deze list eens ; zie file + "SCREEN0V.BKE" + + We proberen nu een patroon te vinden voor het zetten van de + kruisjes op een stategische manier. Het beste is om in het + midden te beginnen en zo naar buiten te werken. Het is dus + afwachten wat de speler doet. + + Er is ook nog verschil tussen de versie waarbij de speler en + de versie waarbij de computer begint. Om het patroon zelf te + vinden is het spelen van het spelletje (heeel vaak!!) nodig + om het patroon te vinden. Er zijn natuurlijk meerdere + patronen mogelijk (goede en slechte ; daarmee kunnen levels + worden gemaakt : eerst het slechte en dan steeds een beter + patroon). Dit neemt wel veel plaats in beslag!! We beperken + ons nu tot ��n versie, maar dan wel een die de eigenlijke + uitkomst van boter-kaas-en-eiren (altijd) laat uitkomen : + + ALS ER GOED GESPEELD WORDT KAN NIEMAND WINNEN !!!!!!!!!!!!!!! + + De computer zal ook nooit winnen, behalve als de speler een + fout maakt. Het patroon ziet er nogal ingewikkeld uit : + + SPELER BEGINT + ------------- + 1. Kijk of midden vrij is , zo ja , zet in 't midden, anders + zet op een hoek + 2. Kijk waar de speler kan scoren en sluit deze weg af. + 3. goto 2. behalve als de speler een fout maakt en de weg + vrij is om zelf te scoren. + + Dit patroon is vrij eenvoudig omdat het alleen bij de eerste + beurt een speciale zet doet, en anders iedere keer de wegen + afsluit voor de tegenstander. + + De volgende keer volgt de rest van BKE en we gaan het + spelletje EXPLOSIE maken .... + + C YA NEXT TIME !!!! + + T O M " A T L A N T I S " W A U B E N diff --git a/future_disk/13/machinetaal_12.md b/future_disk/13/machinetaal_12.md new file mode 100644 index 0000000..e39caaa --- /dev/null +++ b/future_disk/13/machinetaal_12.md @@ -0,0 +1,145 @@ + + ---- Mcode cursus #12 ---- + + ���� ���� + ���� ���� + ���� ���� + ���� ���� + + + De vorige keer geen Mcodecursus, omdat Ruud en ik even een + weekje waren skieen en dus hele andere dingen aan onze kop + hadden dan een mcodecursus.(NvdR: en thuis met twee gebroken + benen op bed lagen) + + Deze keer behandel ik de PSGregisters 14 en 15. + + Deze 2 registers van de PSG worden op de MSX gebruikt voor + het uitlezen van de beide spelingangen, in de volksmond + beter bekend als de joystick-poorten. + + De aansluiting voor de spelingangen zijn 2 vrouwelijke (Ja, + de MSX is dus een zij!!) 9-pins AMP-aansluitingen en zijn + als volgt ingedeeld: + + ************************************* + * * + * *** *** *** *** *** * + * * 1 * * 2 * * 3 * * 4 * * 5 * * + * *** *** *** *** *** * + * * + * *** *** *** *** * + * * 6 * * 7 * * 8 * * 9 * * + * *** *** *** *** * + * * + ******************************* + + Pin nr. Naam Signaal Richting + + 1 FWD IN + 2 BACK IN + 3 LEFT IN + 4 RIGHT IN + 5 +5 V --- + 6 TRG 1 IN/UIT + 7 TRG 2 IN/UIT + 8 OUTPUT UIT + 9 GND --- + + PSG register 14 kan alleen gelezen worden. De bits van dit + register hebben de volgende betekenis: + + Bit 7 Cassete-ingangsignaal + Bit 6 ???? + Bit 5 invoersignaal pin 7 + Bit 4 invoersignaal pin 6 + Bit 3 invoersignaal pin 4 + Bit 2 invoersignaal pin 3 + Bit 1 invoersignaal pin 2 + Bit 0 invoersignaal pin 1 + + PSG register 15 kun je zowel lezen als schrijven. Voor de + betekenis van de bits geldt: + + Bit 7 ???? + Bit 6 keuze spelingang 1 of 2 (1=ingang 2) + Bit 5 uitvoersignaal pin 8 ingang 2 + Bit 4 uitvoersignaal pin 8 ingang 1 + Bit 3 uitvoersignaal pin 7 ingang 2 + Bit 2 uitvoersignaal pin 6 ingang 2 + Bit 1 uitvoersignaal pin 7 ingang 1 + Bit 0 uitvoersignaal pin 6 ingang 1 + + + Deze registers kun je gewoon gebruiken als normale PSG + registers en je kan dus gewoon via poort #A0 het nummer van + het register schrijven (14 of 15) en dan met poort #A1 een + waarde inschrijven of met poort #A2 de waarde van het + register lezen. + + Wat hebben we nu aan deze wetenschap ??? + + Via deze 2 spelingangen kunnen we joysticks (genotsknotsen), + muizen, touchpads, lichtpistolen etc. etc. op de MSX + aansluiten. Ook kan er zo een verbinding tussen 2 + MSXcomputers tot stand worden gebracht, je kunt immers + lezen en schrijven (in beperkte mate) via deze poorten. Er + bestaat zelfs een boek dat "Kreatief met Spelingangen" + omgaat: Electronicaprojecten voor MSX-Computers. Dit boekje + ligt nog voor geen tientje bij de meeste "de Slegte"- + boekhandels. Wie weet brengt dit nog iemand op het idee om + een SNES-scope via de spelingangen te besturen. + + Tot slot nog een listinkje voor de Codefreaks: + + + ORG #C000 + + DB #FE + DW ST,EN,ST + + ;PSG Lees + ;Leest de inhoud van ingang 1 en 2 + + ST: + DI + LD A,15 + OUT (#A0),A + LD A,%00000000 + OUT (#A1),A ; Ingang 1 aanzetten + LD A,14 + OUT (#A0),A + IN A,(#A2) ; Ingang 1 lezen + LD (STCK1),A + LD A,15 + OUT (#A0),A + LD A,%01000000 + OUT (#A1),A ; Ingang 2 aanzetten + LD A,14 + OUT (#A0),A + IN A,(#A2) ; Ingang 2 lezen + LD (STCK2),A + EI + RET + STCK1: DB 0 + STCK2: DB 0 + EN: END + + Wil je echt nog wat meer over deze registers te weten komen + dan raad ik je aan om eens de BIOSroutines #D5,#D8 en #DB te + disassemblen. Dit zijn namelijk respectievelijk de + Joystickuitlees, de Joystickknoppenuitlees en de muisroutine + van de MSX. + + Mijn grote dank gaat uit aan A.Rensink voor de informatie + over dit onderwerp. + + + Veel programmeerplezier van: + + Jan-Willem van Helden + en Ruud Gelissen + + P.S. Ja, sorry dat dit zo'n korte cursus is, maar Hegega + moet Bet Your Life nog afmaken en dus staat de programmeer- + cursus effe op een wat lager pitje ..... diff --git a/future_disk/13/pascal_3.md b/future_disk/13/pascal_3.md new file mode 100644 index 0000000..2323138 --- /dev/null +++ b/future_disk/13/pascal_3.md @@ -0,0 +1,153 @@ + * Pascal (3) * + + + Welcome to the third PASCAL course. Ofwel, hallo, dit is de + derde PASCAL cursus op de FD. Het mag dan wel FD #13 zijn, + maar aangezien de PASCAL cursus pas zijn derde nummer ingaat + zou alles dus helemaal okie dokie moeten zijn. Wat een gezeur + h�! Ik zal maar beginnen, voor ik nog meer onzin uitkraam. + + Vorige keer heb ik het over Koen gehad (helemaal in het begin) + en ja hoor, hij had weer iets te zeiken, dus nu even mijn + antwoord: "Ja Koen, je kunt ook 100 minuten bandjes door mijn + programma laten uitrekenen.". Zo, dat is ook weer opgelost. + (NvdR: ja stomme ezel, dat had ik ook al door!) + + Nu even echt serieus. Deze keer ga ik lussen bespreken. In + PASCAL zijn drie soorten lussen: FOR-TO-DO, REPEAT-UNTIL en + WHILE-DO. Uit de namen kan al ��n en ander afgeleid worden. + Maar ik zal de verschillende lussen met een voorbeeld + behandelen. + + Stel ik wil de getallen 1 t/m 10 op het scherm toveren. Hoe + doe ik dat? Hier komen de drie mogelijkheden: + + FOR-TO-DO: + + PROGRAM ForNext (input,output); + + VAR + teller : integer; + + BEGIN + FOR teller := 1 TO 10 DO + writeln(teller); + END. + + REPEAT-UNTIL: + + PROGRAM RepeatUntil (input,output); + + VAR + teller : integer; + + BEGIN + teller := 0; + REPEAT + teller := teller + 1; + writeln(teller); + UNTIL teller = 10 + END. + + WHILE-DO: + + PROGRAM WhileDo (input,output); + + VAR + teller : integer; + + BEGIN + teller := 0; + WHILE teller < 10 DO + BEGIN + teller := teller + 1; + writeln(teller); + END; + END. + + Dat waren ze. Maar nu de uitleg. In het eerste voorbeeld + (FOR-TO-DO) zie je, dat de variabele "teller" van 1 t/m 10 zal + lopen. Er staat tenslotte dat de teller zal lopen van 1 tot en + met 10, en zolang moet je teller afdrukken. Een FOR lus kan + niet worden onderbroken (voor de echte crack wel, maar dat is + met een GOTO en dat is weer niet gestructureerd en dus niet + netjes). Een FOR lus loopt altijd van onder- tot bovengrens. + Nu denk je natuurlijk: Ik wil ook van 10 naar 1 kunnen lopen, + dat kan, maar dan moet je DOWNTO in plaats van TO gebruiken. + Voor de goede orde: Als de ondergrens groter is dan de + bovengrens (FOR teller := 2 TO 1 DO) dan gebeurt er dus + niets. + + Het tweede voorbeeld (REPEAT-UNTIL) werkt heel anders. Hier + wordt de lus op een bepaalde conditie verlaten. In het + voorbeeld staat dan ook HERHAAL ... TOTDAT teller=10. Zolang + teller niet 10 is, gaat de lus door. Probeer maar eens wat er + gebeurt als je de regel "teller := teller + 1;" weglaat. Je + zult zien dat de lus eindeloos doorgaat; teller wordt ook + nooit 10. + + Het verschil met het tweede en derde voorbeeld is eigenlijk + minimaal. Ook hier wordt de lus verlaten bij een bepaalde + conditie (teller=10), alleen wordt hier eerst gecontroleerd en + daarna pas beslist of de lus doorlopen moet worden. Het grote + verschil is dan ook dat de REPEAT-UNTIL minimaal 1 maal + doorlopen wordt, terwijl dat bij de WHILE-DO niet het geval + is. + + Zo, dat was een snel overzicht van de lus functies in PASCAL. + En nu maar oefenen. Tja, ik kan het niet vaak genoeg zeggen, + veel oefenen, anders leer je het niet. Ik zal, hoewel vorige + keer niemand een reactie heeft gegeven(gek h�) (NvdR: ligt + gewoon aan jou!), ook deze keer wat opdrachten geven. + + OPDRACHTEN: + (1) Maak een programma dat alle mogelijke combinaties van 4 + (hoofd)letters op het scherm zet (doe dit met alleen + FOR-TO-DO, REPEAT-UNTIL of WHILE-DO lussen). + (2) Maak een programma dat alle priemgetallen tot een + ingegeven getal berekend (doe ook dit met alleen + FOR-TO-DO, REPEAT-UNTIL of WHILE-DO lussen). + + Voordat jullie kunnen beginnen moet ik nog even snel wat + uitleggen over compound-statements. In PASCAL is het namelijk + zo, dat na bepaalde opdrachten (FOR-TO-DO, WHILE-DO, + IF-THEN-ELSE) maar ��n opdracht mag staan. Bij de FOR-TO-DO + lus mag dus niet staan: + + WHILE teller < 10 DO + write(teller); + teller := teller + 1; + + De opdracht "write(teller)" is namelijk 1 opdracht en de + volgende opdracht "teller := teller + 1" zou pas worden + uitgevoerd als de WHILE-DO lus voorbij is (nooit(!)). Vaak is + het echter noodzakelijk dat meerdere opdrachten in een lus + worden uitgevoerd. De oplossing hiervoor is het compound- + statement. Een compound-statement is een heleboel statements + omgeven door een BEGIN en een END. Het voorbeeld zal dus + worden: + + WHILE teller < 10 DO + BEGIN + write(teller); + teller := teller + 1; + END; + + Bij het bovenstaande programma zal alles wel naar wens + verlopen. Samenvattend komt het er op neer dat als je bij + lussen (REPEAT-UNTIL is hier de bevestigende uitzondering) + meerdere statements wil laten uitvoeren, dat je die statements + moet laten voorafgaan door BEGIN en eindigen met END. + + Zo, met bovenstaande informatie moet je in staat zijn om de + zes opdrachten te maken. + + Veel plezier, + + ���� Jeroen "KUBIE" Smael + ���� Galopiahof 6 + ���� 6215TK Maastricht + ���� Telefoon : 043-437778 + + C YA @!! + diff --git a/future_disk/14/pascal_4.md b/future_disk/14/pascal_4.md new file mode 100644 index 0000000..e9a4c14 --- /dev/null +++ b/future_disk/14/pascal_4.md @@ -0,0 +1,150 @@ + + PASCAL (4) + ========== + + Programmeren is masochisme, maar wat is het lekker(NvdR:??). + Nou ja, als je aan het programmeren BENT niet, maar als het + werkt en die kl*t* machine doet eindelijk precies wat JIJ + wilt, dat is pas een hoogtepunt. Waarom vertel ik dit + allemaal? Als eerste omdat ik een reactie van Koen wil + uitlokken (h� etter, waar ben je)(NvdR: hiero!) en als + tweede een meer belangrijke reden (Koen is tenslotte niet + belangrijk)(NvdR: moet je iemand horen!) om je te stimuleren + om toch vooral door te gaan, want uiteindelijk lukt het + wel[ (dat MSX'je kan veel meer dan je denkt). + + Deze vierde aflevering van mijn PASCAL cursus is gewijd aan + PROCEDURE's en FUNCTION's. In elke programmeertaal ontstaat op + een bepaald moment behoefte aan funkties en procedures. + Waarom? Nou, gewoon, omdat je geen zin hebt om een bepaald + stuk code dat je vaker nodig hebt (bijvoorbeeld een invoer + routine) ook vaker in te tikken. Als je het geheel ��n keer + hebt ingetikt, dan wil je het vaker gebruiken, niet alleen + omdat je maar ��n keer wil tikken, maar ook omdat dat stuk het + doet en je bij overtikken fouten kunt maken. + Wat is nu het verschil tussen FUNCTION en PROCEDURE? Het + verschil zit 'm in de uitkomst. FUNCTION heeft een uitkomst, + PROCEDURE niet. Een heel eenvoudige FUNCTION ziet er als volgt + uit: + + FUNCTION Optel(Getal1:integer;Getal2:integer):integer; + BEGIN (* Optel *) + Optel := Getal1 + Getal2; + END; (* Optel *) + + Bovenstaande funktie is dus niets. Je zou hem nooit gebruiken + in een programma, omdat optellen al standaard aanwezig is. Wel + zou je een funktie schrijven om machten te berekenen, omdat + dat niet standaard in PASCAL aanwezig is. Het voorbeeld geeft + wel duidelijk de struktuur van een funktie weer. + Als eerste staat het gereserveerde woord FUNCTION, waarna de + naam van de funktie volgt (let op; gebruik hiervoor geen + gereserveerde woorden!). Tussen haakjes volgen de variabelen + die je nodig denkt te hebben in de funktie tesamen met hun + type (dit stuk is niet verplicht, omdat je niet altijd + variabelen nodig hebt, denk hierbij aan een random funktie). + Als laatste volgt er nog het type van de uitkomst van de + funktie. + + Na deze eerste regel volgt de body van de functie, die + overigens precies gelijk is aan de body van een programma + (ook hier kun je variabelen declareren en andere funkties of + procedures maken). In het code gedeelte is slechts een ding + verplicht en dat is het toekennen van een waarde aan de + funktie (in het voorbeeld "Optel := Getal1 + Getal2"). Doe + je dit niet, dan krijg je gegarandeerd een foutmelding. + Een klasieke fout is overigens het volgende: + + Optel := 0; + FOR Teller := 1 TO 10 DO + Optel := Optel + Getal[Teller]; + + Hiermee zou je een ARRAY kunnen optellen (denk je), maar het + is verboden om de naam van de funktie (Optel) rechts van het + toekenningsteken te plaatsen en dus werkt het niet. Om het wel + aan de praat te krijgen zul je een variabele "Som" moeten + declareren en het volgende moeten doen: + + Som := 0; + FOR Teller := 1 TO 10 DO + Som := Som + Getal[Teller]; + Optel := Som; + + Zo, nu is de uitleg van een procedure een makkie (dus niet). + Eerst een voorbeeld: + + PROCEDURE Uitkomst(Getal:integer); + + BEGIN (* Uitkomst *) + Writeln('De uitkomst is : ',Uitkomst); + END; (* Uitkomst *) + + Alweer zo'n gemakkelijk voorbeeldje (anders begint Koen te + klagen dat 'ie 't nie begrijp, eikel!).(NvdR: leer jij maar + eens een tekstroutine programmeren!) Je ziet dat de struktuur + nagenoeg gelijk is. + Een procedure heeft geen uitkomst en dat blijkt uit de eerste + regel (heading). Verder mag de procedure geen waarde krijgen + (Uitkomst := 10 is dus uit den boze). Voor de rest is alles + gelijk (er mogen dus ook variabelen gedeclareerd en funkties + of procedures gemaakt worden). + + Je weet nu bijna alles van funkties en procedures, ik moet + alleen nog parameter variabelen uitleggen. Bij een funktie of + procedure geef je gewoonlijk ��n of meer variabelen mee, + alleen, je geeft ze niet mee, je copieert ze. Wat ik bedoel + is, dat de waarde die een variable bezit bij aanroep van de + funktie of procedure, wordt gecopieerd. Aanchouw het volgende + voorbeeld: + + FUNCTION T1(Getal1:integer;Getal2:integer):integer; + + BEGIN (* T1 *) + T1 := Getal1 + Getal2; + Getal1 := Getal1 * 2; + END; (* T1 *) + + En vervolgens in het hoofdprogramma de volgende opdrachten: + + A := 10; + B := 20; + Iets := T1(A,B); + + Deze funktie heeft value parameters, wat betekent dat bij de + aanroep wordt gekeken wat de waarde van de formele parameters + (A en B) is en die gecopieerd wordt naar de actuele parameters + (Getal1 en Getal2). De uitkomst is (hoe kan het anders) 30. De + vraag is echter, wat wordt A? In dit geval veranderd A NIET (A + blijft 10). De copie (Getal1) verandert, maar de formele + parameter (A) blijft gelijk, er bestaat geen link. Daarom + noemt men dit value parameters ofwel waarde parameters, alleen + de waarde wordt doorgegeven. + De andere variabelen zijn parameter variabelen. Een funktie of + procedure met parameter variabelen ziet er als volgt uit: + + FUNCTION T2(VAR Getal1:integer;Getal2:integer):integer; + + BEGIN (* T2 *) + T2 := Getal1 + Getal2; + Getal1 := Getal1 * 2; + END (* T2 *) + + Herhalen we nu de aanroep, dan veranderd A wel in 20. A wordt + nu namelijk als referentie meegegeven. Alle bewerkingen op + Getal2 vinden nu rechtstreeks plaats op A. + + Zo, dat was alles wat ik over funkties en procedures kwijt + wilde. Als oefening deze keer kun je alle voorgaande + oefeningen opnieuw doen, alleen met dit verschil dat je in + het hoofdprogramma alleen maar aanroepen doet naar funkties + of procedures. Oh ja, natuurlijk niet maar een procedure + waarin het hele hoofdprogramma gecopieerd wordt (dan heeft + het oefenen nog geen nut). Oefen trouwens ook lekker veel + met het verschil tussen parameter en value parameters. + + Groetjes, + + Jeroen 'KUBIE' Smael + + C YA @!! + diff --git a/future_disk/15/data_compressie.md b/future_disk/15/data_compressie.md new file mode 100644 index 0000000..a8d3e06 --- /dev/null +++ b/future_disk/15/data_compressie.md @@ -0,0 +1,103 @@ + Data Compressie + + ���� De machinetaal-cursus is naar mijn idee be�indigd + ���� en daarom sluit ik dat dossier en begin met een + ���� cursus. Je denkt misschien:"Hee, die titel heb ik al + ���� eens in de MCCM zien verschijnen??? Schreven Falco + en Ivo daar niet pagina's over vol ???" + + Inderdaad Ivo en Falco schreven er pagina's over vol, maar + lieten je vaak zitten met aanwijzingen hoe het moest en + bespraken maar twee methoden van compressie. In deze cursus + wil ik er een stuk dieper op ingaan dan Falco en Ivo en + lever ik kant en klare PD crunch-routines af, om in je eigen + programma's te gebruiken. Maar laten we eerst het nut van + datacompressie eens bespreken. + + Het nut van datacompressie is, zoals de naam al zegt, het + samenpakken van de orginele data tot een kleiner geheel. Ook + de mogelijkheid om vele files in 1 file samen te pakken, + maakt datacompressie een fijn hulpmiddel om �n ruimte te + besparen, �n overzicht te houden. + + Datacompressie deed zijn intrede rond de tijd van de eerste + harddisks. Plotseling hadden gebruikers 5 MB aan + opslagruimte i.p.v. de 360 KB op een diskette of nog minder + op een cassette. De gebruikers wilden deze opslagruimte zo + efficient mogelijk gebruiken om er zoveel mogelijk + programma's op te zetten. Ook hadden ze voor de uitwisseling + data op de "gewone" diskdrives liefst zo weinig mogelijk + diskettes nodig. Als ze een programma van 5 MB hadden en een + medegebruiker wilde dat programma ook graag hebben (illegale + kopietjes draaien!) wilde men natuurlijk niet met (1 MB/360 + KB) 3 diskettes rond gaan lopen (dan is de pakkans immers + groter) plus dat de man dan zo'n 30 � 40 files zo competent + mogelijk over de diskettes zou moeten verdelen om niet met + nog meer disks over straat te moeten. Daarom werden er + verscheidene compressie methoden uitgedacht door wiskundigen + en informatici om zo compact mogelijk data op te slaan. + + De deskundigen kwamen tot de conclusie dat er in een + data-reeks altijd patronen of repetities van data-elementen + zaten. Deze ontdekking resulteerde in twee methoden van + datacompressie: + + - Het tellen van gelijke opeenvolgende data-elementen en + deze opslaan als data-element + aantal keren opelkaar + volgend voorkomen. + + - Het zoeken naar patronen in de data en deze m.b.v. codes + opslaan. + + De eerste compressie methode heeft het grote nadeel in + bijvoorbeeld tekstfiles. Als er weinig dezelfde elementen + achterelkaar voorkomen, zou het kunnen dat de compressie + zelfs negatief zou gaan werken. Immers, als men aan de + standaard opslag vasthoudt, zou je elk data element opslaan + als: "DATA-ELEMENT + aantal keer opeenvolgend voorkomen" + je dubbel zoveel of meer ruimte nodig had dan het orgineel. + De tweede compressie methode heeft het nadeel dat de + (basis)patronen ongecodeerd moeten worden opgeslagen. + + Het ligt aan de orginele data welke compressie methode het + beste werkt. Een klein voorbeeldje: + + Stel je hebt een leeg SCREEN 8 plaatje. Dit plaatje neemt + (256*212) 54272 bytes aan opslag-ruimte in. Laten we er nu + de eerste compressie methode op los, dan zal het plaatje nog + maar 3 bytes innemen, namelijk "DATA-ELEMENT (0) + aantal + keer opeenvolgend voorkomen (54272)". Dit is een compressie + van 0.00552 % !!!!! + Zou je nu de andere compressie methode erop los laten, dan + zou je (afhankelijk van de patroon zoek methode) altijd een + grotere opslag krijgen dan de 3 bytes van de andere methode. + + Maar.....neem deze tekstfile eens als voorbeeld. Als we hier + de eerste methode op zouden loslaten zouden we een enorme + negatieve compressie krijgen. De opeenvolging van dezelfde + data-elementen (de letters dus) is extreem zeldzaam. Het + woord "Boemel", normaal 6 bytes, zou worden opgeslagen + als: "B"(1)+"o"(1)+"e"(1)"+"m"(1)+"e"(1)+"l"(1) = 12 bytes. + Dit is een compressie van 200%, zeer negatief dus ! + Met de andere methode zou de computer kunnen vinden dat de + "e" als patroon 2x voorkomt en dus een kleinere bitlengte + moet krijgen dan de andere elementen (Huffman-principe). De + compressie zou nog steeds niet groot zijn, maar altijd nog + niet negatief. Alleen de opslag van de patroontabel zou de + uiteindelijke compressiefile weer groter kunnen maken dan + het orgineel. + + Overigens heeft datacompressie natuurlijk geen zin op een + reeks als "ABCDEFGHIJKLMNOP". Hierin is zelfs door mensen + geen patroon of opeenvolging in te vinden dus heeft het meer + zin om deze data "gewoon" op te slaan. De beste compressie + methode zou natuurlijk moeten kijken of de compressie wel + zin heeft, want om negatieve compressie staat niemand te + springen. + + Zo, dit is ongeveer de inleiding en de benodigde achtergrond + kennis om deze cursus te begrijpen en de eruitvoorkomende + programma's zelf te kunnen maken en nieuwe compressiemetho- + den te programmeren. + + Jan-Willem van Helden diff --git a/Future Disk/15/Looplichtje.md b/future_disk/15/looplichtje.md similarity index 100% rename from Future Disk/15/Looplichtje.md rename to future_disk/15/looplichtje.md diff --git a/future_disk/15/pascal_5.md b/future_disk/15/pascal_5.md new file mode 100644 index 0000000..caf0759 --- /dev/null +++ b/future_disk/15/pascal_5.md @@ -0,0 +1,85 @@ + + PASCAL 5 + ======== + + ���� Alweer deel 5 van deze cursus! Wat gaat de tijd toch + ���� snel. Deze keer een kleine cursus, omdat het over + ���� een gemakkelijk onderwerp handeld. Deze cursus + ���� behandeld namelijk het maken van eigen types. + + Bij het declareren van een variabele konden we tot nog toe + alleen maar kiezen uit de standaard type's (integer, real, + boolean, etc.). In PASCAL is het echter ook mogelijk om je + eigen type's te maken en wel als volgt: + + TYPE + OpsomType = {Item1,Item2,Item3}; + SubrangeType = 1..10; + ArrayType = ARRAY[1..10] OF AnderType; + + Je kunt dus een opsommingstype maken bijvoorbeeld: + + DagenVanDeWeek = {Maandag,Dindag,Woensdag,Donderdag,Vrijdag, + Zaterdag,Zondag} + + Of een subrangetype (van elk ander type). Bijvoorbeeld: + + DagenVanDeMaand = 1..31 (* integers dus *) + + Of een ARRAY type. Bijvoorbeeld: + + WekenVanEenJaar = ARRAY[1..52] OF DagenVanDeWeek + + Vervolgens kun je de types gebruiken, maar let wel goed op met + toekenningen e.d. Neem bijvoorbeeld het volgende: + + VAR + Dag : DagenVanDeWeek; + + Dan mag + + Dag:=Maandag; + + Maar niet + + Write("Geef dag : "); + Readln(Dag); + + De type's verschillen immers. Bij Readln lees je een integer, + real of string, maar niet een DagenVanDeWeek. + + Wat ook niet kan is + + Dag:=Maandag; + Writeln("Het is vandaag ",Dag); + + En wel om dezelde reden als bij Readln. Wat wel kan is + + Dag:=Maandag; + CASE Dag OF + Maandag : Write("Maandag"); + Dinsdag : write("Dinsdag"); + . + . + . + + Experimenteer maar eens een beetje met het cre�ren van eigen + type's en je zult zien dat dit heel handig kan zijn. + + Een functie die een beetje met deze type declaratie te maken + heeft is de IN functie. Deze werkt als volgt: + + IF Dag IN {Maandag,Dinsdag,Woensdag,Donderdag,Vrijdag} THEN + writeln("Dit is een werkdag"); + + Je kunt dus met IN kijken of de waarde van een variabele in + een gegeven verzameling zit. Die verzameling moet je wel eerst + opsommen, maar dat is een kleine prijs om te betalen tegenover + (in dit geval) 5 IF statements. + + Zo, dit was kort maar krachtig(NvdR: geloof je dat nou + zelf?). + + Jeroen "Ik beloof beterschap" Smael + + C YA @!! diff --git a/future_disk/15/the_2+_corner.md b/future_disk/15/the_2+_corner.md new file mode 100644 index 0000000..e801201 --- /dev/null +++ b/future_disk/15/the_2+_corner.md @@ -0,0 +1,118 @@ + The 2+ Corner + + + Veel mensen weten nog steeds niet wat de MSX2+ allemaal + extra biedt t.o.v. een MSX2. Natuurlijk iedereen weet dat + de 2+ veel meer kleuren heeft dan een MSX2 en dat hij een + hardware scroll heeft, maar er zijn wel wat meer dingen + verandert... + + Kun-Basic + + Een 2+ heeft een ingebouwde Kun-Basic die door middel + van _BC uit basic opgeroepen kan worden. Vooral als + je zelf vaak in basic programmeert kan dit heel + handig zijn. + + Kanji-basic + + Hoewel Kanji-basic op het eerste gezicht een beetje + nuttleloos lijkt is het soms toch best wel handig b.v. je + wilt een keer een file menu maken in screen7 in gewoon + basic moet je dan een best ingewikkelt programma maken om + de files op het scherm te krijgen in Kanji-basic zet je + gewoon FILES in je programma en... HOP; je hebt de files in + screen 7. Ook kan je in elk scherm de commando's PRINT en + LOCATE gebruiken dus geen gemier met OPEN"grp:" FOR OUPUT + AS #1. + Simpel toch. (kanji-basic zit ook in de dos2.XX cartridge) + + Hardware scroll + + E�n van de beste uitbreidingen op een 2+ is wel het scroll + commando. Dankzij die hardware Scroll kan je simpel, �n elk + scherm in elke richting scrollen. + + Commando functie + + Met R#46 kan je commando's geven aan de VDP zoals + copy, line, point,ect,ect maar die commando's werken echter + op een MSX-2 alleen in de schermen 5 to 8. Op een 2+ kan + dit in elk scherm als je de commando functie aan zet + in R#25 (bit 6). + + Wait functie + + In R#25(NvdR: in Basic is dit VDP(26)) kan je ook de wait + functie aan zetten (bit2). + Dat zorgt er voor dat wanneer de CPU naar het Vram schrijft + alle poorten van de V9958 in de wacht mode worden gezet. + Hierdoor wordt de schrijftijd van de CPU naar het vram + verkleind. + + Reset + + Na een reset wordt er gezorgt dat gekraakte Rom's ed niet + weer opstarten, dit is vooral handig voor de Sony mensen + onder ons die soms wel ��n minuut moeten wachten voordat + een spel uit het geheugen is. Het geheugen wordt niet + gewist, want dan zou een reset bestendige ramdisk na een + reset wel weg zijn. + + Opstarten + + Bij het opstarten van de 2+ wordt al het geheugen bij + elkaar opgeteld, dit in tegen stelling tot een MSX2. + Een MSX2 print gewoon op het scherm wat er standaard in zit + en bij sommige MSX computers geeft hij bij het opstarten + helemaal niet aan hoeveel ram er aanwezig is. + + Nieuwe schermen + + Ja, hier valt weinig over te zeggen alleen dat digi's gewoon + veel mooier op screen 12 zijn dan in screen 8. + Het leuke van screen 11 is dat je daar naast de 12499 YJK + kleuren ook nog 16 RGB kleuren hebt waarmee je de color + spil weg kan werken. + By the Way het enige verschil tussen screen 10 en 11 is hoe + basic 3.0 er mee omgaat in ML is er geen verschil. + Daar is gewoon geen screen 10. + (iemand enig idee waarom screen 9 niet bestaat?) + (NVDR: SCREEN 9 werd opgekocht door een Koreaans bedrijf dat + SCREEN 9 zo gebouwd heeft dat de Koreaanse karakterset erin + gebruikt kan worden! SCREEN 9 is dus alleen ingebouwd in + alle Koreaanse MSX-2's!) + + Wat mij opvalt is dat er veel meer 2+ computers zijn dan + sommige mensen denken. Als je aan sommige programmeurs + vraagt waarom ze niets voor de 2+ maken dan zeggen ze dat + de 2+ niet veel extra's biedt, maar daar ben ik het niet mee + eens... + Kijk nou eens naar het spel LAYDOCK 2 Last Attack + Heeft iemand zo'n mooi spel op de MSX-2 gezien? Omdat de + MSX-2 niet goed kan horizontaal scrollen (NVDR: LEES OMDAT + JE MET DE V9938 NIET...) in de schermen 5 to 8, zijn + de spellen die horizontaal scrollen meestal in screen 4 + gemaakt. Zie bijvoorbeeld Hydefoss, Psycho World, Space + Manbow, en zo kan ik nog wel even doorgaan. De graph-x in + die spellen hebben er dan ook aan te lijden. Op een 2+ + zouden die spellen veel mooier kunnen... + + In de MCCM stond bij de recensie van Mega doom dat je + moest oppassen dat dit spel 128KB nodig heeft. Wie heeft er + tegenwoordig nog 64KB? Misschien is er nog 1 persoon in + Nederland die een MSX2+ met 64KB heeft, maar dat lijkt me + wel heel erg onwaarschijnlijk. Met 64KB kan je bijna geen + software draaien... + + Als je een GIF freak en je hebt een MSX-2 dan zou ik je + computer maar laten ombouwen naar een 2+, want in screen 12 + zijn Gif plaatjes gewoon zo als ze moeten wezen en niet met + allemaal vieze kleuren zoals in screen 8. + + Marcel Otten + + PS OP FUTUREDISK #16 STAAN ENKELE KLEINE PROGRAMMAATJES VAN + MARCEL, GENAAMD "SCROLL.LDR" en "4096.LDR" + DEZE PROGRAMMA'S WERKEN NATUURLIJK ALLEEN OP MSX-2+ of + TURBO-R. LET OP; SCROLL.LDR werkt ALLEEN met MUIS! diff --git a/future_disk/17/basic_cursus_6.md b/future_disk/17/basic_cursus_6.md new file mode 100644 index 0000000..e4919cf --- /dev/null +++ b/future_disk/17/basic_cursus_6.md @@ -0,0 +1,117 @@ + BASIC Cursus?! + +���� Okay mensen. Tom ligt er uit (Yes!) en Tobias herstart +���� bij deze dus de BASIC cursus. Natuurlijk kan Tobias niet +���� verder gaan waar Tom gebleven was. In de eerste plaats +���� niet omdat Tom een eikel is en in de tweede plaats + omdat Tobias' aanpak compleet anders is. Wij bedanken U +voor Uw begrip. Het woord is aan Tobias... + + BASIC CURSUS (6) + + ���� + ���� + ���� + ���� + + SHIFT en ander gekakel... + + + Toen ik een klein jongetje was had ik maar ��n droom. + (Waag 't niet Koen!) Ik wou zo graag de Shift toets en dat + soort onzin toetsen uitlezen(NvdR: and that's your dream?). + Maar ja, met inkey$ ging dat zo moeilijk. Toen ging ons + Tobiasje naar een oude wijze Guru. Roman van der Meulen. + Roman was alleen een beetje lui en riep alleen 't woord + "Toetsen bord buffer" uit om vervolgens weer te gaan slapen. + Toen ging ons Tobiasje maar naar een andere wijze Guru: + Jan van Valburg. Maar Jan was nogal druk met allerlei + vunzige bezigheden achter z'n computer (WIDEOPEN.GIF) en kon + ons Tobiasje ook niet helpen. Ten einde raad ging ons + Tobiasje huilend terug naar huis, nog steeds niet wetend hoe + hij de Shift toets moest uitlezen. Toen kwam Tobiasje een + minstens 50 kilo te zware, wild behaarde, en veel te naive + hippie tegen: Wammes Witkop. Wammes had een eigen blad voor + MSX en kende dus heel veel mensen. Ook kende hij iemand die + wel graag toetsen uitlas: Hayo Rubingh(NvdR: dat was vroeger + ook echt mijn hobby!). Hayo was echter druk bezig andere + muziek-programma's af te zeiken en verwees Tobiasje door + naar Albert Huitsing die eigenlijk 't hele MIDI gedeelte + heeft gedaan waar Hayo altijd de eer van opstreek/opstrijkt. + Albert kon Tobiasje wel helpen en legde het volgende uit: + + OK lieden, het hele gezeik over de interrupt en al dat geemmer + over hoe al die data in de toetsen bordbuffer komt ga ik + niet weer helemaal uitleggen. Als je dat niet weet zoek je + maar de dichtst bijzijnde brug op. KEYBUF ga ik niet + behandelen omdat die niet zo gek interressant is. NEWKEY + echter is veel interressanter. NEWKEY loopt van &HFBE5 tot + &HFBEF en is dus 11 bytes groot. Wat precies klopt gezien + 't feit dat er 11 rijen zijn. NEWKEY kan vanuit BASIC gewoon + met een PEEKje worden uitgelezen alleen dan is 't wel + belangrijk om de matrix van zowel de Jappen als de + internationalen te weten. Die rommel die toen door PHILIPS + en SONY is gemaakt wilt nog wel eens moeilijk doen, maar + voor zover ik weet klopt die int. matrix wel redelijk. Eerst + de beide matrixen: + + Toetsenbord matrix Europeaan: + + Adres Rij B i t n u m m e r + 7 6 5 4 3 2 1 0 + + &HFBE5 0 7 6 5 4 3 2 1 0 + &HFBE6 1 ; ] [ \ = � 9 8 + &HFBE7 2 B A ACC / . , ` ' + &HFBE8 3 J I H G F E D C + &HFBE9 4 R Q P O N M L K + &HFBEA 5 Z Y X W V U T S + &HFBEB 6 F-3 F-2 F-1 CODE CAPS GRPH CTRL SHFT + &HFBEC 7 RET SEL BS STOP TAB ESC F-5 F-4 + &HFBED 8 RGHT DOWN UP LEFT DEL INS HOME SPC + &HFBEE 9 4 3 2 1 0 not not not numeriek + &HFBEF A . , � 9 8 7 6 5 eiland + + Toetsenbord matrix Japanner: + + Adres Rij B i t n u m m e r + 7 6 5 4 3 2 1 0 + + &HFBE5 0 7 6 5 4 3 2 1 0 + &HFBE6 1 ; [ @ Yen ^ � 9 8 + &HFBE7 2 B A _ / . , ] : + &HFBE8 3 J I H G F E D C + &HFBE9 4 R Q P O N M L K + &HFBEA 5 Z Y X W V U T S + &HFBEB 6 F-3 F-2 F-1 KANA CAPS GRPH CTRL SHFT + &HFBEC 7 RET SEL BS STOP TAB ESC F-5 F-4 + &HFBED 8 RGHT DOWN UP LEFT DEL INS HOME SPC + &HFBEE 9 4 3 2 1 0 not not not numeriek + &HFBEF A . , � 9 8 7 6 5 eiland + + + Nu je beide matrixen hebt kun je al aan de slag. Met een + ordinairde PEEK valt 't gewenste adres uit te lezen. Is een + bit 0 dan is de betreffende toets ingedrukt. Om dus te kijken + of de shift toets is ingedrukt, zoals kleine Tobiasje dat + wilde, maken we dus 't volgende listinkje: + + 10 IF PEEK(&HFBEB)<>&B11111111 THEN PRINT"J" ELSE PRINT "N" + + Maar een ieder kan zien dat dit niet echt netjes is, wordt + namelijk F-1 ingedrukt, verschijnt er ook J in beeld. F-1 + staat immers ook in rij 6. Maar hoe test je nu op alleen + bit 0 van rij 6? Simpel, 't zooitje ANDen. Dan krijg je dus: + + 10 IF (PEEK(&HFBEB)AND&B00000001)=0 THEN PRINT"J" + + Natuurlijk mogen de rijen en kolomen verschillen maar dit is + wel zo'n beetje hoe je 't best 't keyboard kan uitlezen. Dit + is overigens ook handig als er iets ingevoerd moet worden maar + je dit niet aan de basic interpreter wil overlaten. Ook voor + pull-down menutjes -die vaak met een non�active toets + geactiveerd worden- is dit handig. Well folks, that's about + it for today... next time I'll errr... well I don't know, but + it'll be more usefull than this shit.... bye + + Tobias 'fushigi' Keizer diff --git a/future_disk/17/data_compressie_2.md b/future_disk/17/data_compressie_2.md new file mode 100644 index 0000000..cc66702 --- /dev/null +++ b/future_disk/17/data_compressie_2.md @@ -0,0 +1,141 @@ +---- Data Compressie (2) ---- + + ���� Er wordt dit keer begonnen met het echtere werk. + ���� De aflevering van de vorige keer was een inleiding + ���� op hetgene wat ik in de volgende cursi zal behandelen. + ���� + + + Allereerst beginnen we nog eens met de grondregel van + datacompressie: we willen een groot geheel als een kleiner + geheel opslaan. + + Om dit te doen kennen we verschillende methoden. Dit keer + beginnen we met de makkelijkste methode: + + ---- RUNLENGTH ---- + + Falco en Ivo Wubbels schreven er al over en plaatsten een + source in de MCCM die wel erg 'basic' was. Daarom zullen we + proberen een zo groot mogelijke compressie te behalen + met behulp van Runlength-encoding. Maar eerst wat meer over + Runlength. + +---- Wat is RUNLENGTH ??? ---- + + Runlength is een compressie-methode die ervan uitgaat dat er + lange reeksen van gelijke data-elementen in een bestand + voorkomen. Deze reeksen verkleint runlength door de + achtereenvolgende gelijke data-elementen te tellen en ze als + [Waarde] + [Aantal keer opeenvolgend] op te slaan. + +---- RUNLENGTH ALGORITHME ---- + + Om dit te verduidelijken, kijken we eens naar het volgende + voorbeeld, dat de algorithme voor het opslaan van runlength + voorstelt: + + [0] TELLER = 1; + [1] LEES DATAELEMENT; + [2] {X} <- VOLGENDE DATAELEMENT IN BESTAND; + [3] IS DATAELEMENT GELIJK {X} ?; + + (JA: VERHOOG TELLER; + GA NAAR [2]; + ) + (NEE: STUUR DE WAARDE VAN HET DATAELEMENT + AANTAL + KEER VOORKOMEN NAAR DE CODE; + GA NAAR [0]; + ) + + ---- SOURCE LISTING ---- + + Met deze pseudo-code kunnen we makkelijk een assembly- + listing maken: + + ; RUNLENGTH + ; (c) 1994 FutureDisk + + DATA: EQU #A000 + CODE: EQU #B000 + + ORG #C000 + + LD C,1 ;C = teller + + LD HL,DATA ;orginele data + LD DE,CODE ;output opslag + OPNIEW: + LD A,(HL) ;lees eerste data- + ;element + LOOP: + INC HL + CP (HL) ;vergelijk volgende + ;element + JP NZ,NGELYK + INC C ;gelijk: verhoog de + ;teller + JP LOOP ;onderzoek volgende + ;element + NGELYK: + LD (DE),A ;sla het data-element + ;op + INC DE + LD A,C + LD (DE),A ;sla de teller op + INC DE + LD C,1 ;reset de teller + JP OPNIEW ;neem ongelijke + ;element als nieuw + ;data-element. + END + + + Zoals je al ziet gaat deze routine eeuwig door. Dit is + natuurlijk makkelijk te verhelpen door bij elke verhoging + van HL te bekijken of deze is aangekomen bij het einde van + de te comprimeren reeks. + +---- UITGEWERKT VOORBEELD ---- + + Nu de algoritme en een kleine source-listing gemaakt zijn + gaan we eens kijken naar een klein getallen voorbeeldje: + Onze originele data ziet er zo uit: 'AAABBACCCDDDD' + Gaan we stap voor stap door de algoritme. Als eerste + data-element nemen we de A. We vergelijken die met het + volgende element. Alweer een A --> we verhogen de teller en + bekijken het volgende element, weer A --> teller+1 en bekijk + volgende element, een B. We slaan nu het data-element A op + en plaatsen daarachter de teller. De code is nu 'A3'. We + nemen nu de B als data-element, zetten de teller weer op 1 en + vergelijken B met het volgende element --> weer een B, + vergelijken met het volgende element --> een A. We slaan B op + en daarachter de teller. De code is nu 'A3B2'. We zetten de + teller op 1, nemen A als data-element en vergelijken met de + volgende --> een C. We slaan de A op, daarachter de teller, + code is 'A3B2A1', zetten teller op 1 en nemen C als + data-element. C komt 3 keer voor en D nog 4 maal, dus de + code wordt 'A3B2A1C3D4'. Je ziet dat er een kleine + compressie is behaald. Toch komt in dit voorbeeld ook al 1 + van de nadelen van runlength boven water, namelijk het + opslaan van de A tussen de B en de C. Deze A komt maar 1 + keer in het orgineel voor, maar neemt twee elementen in in + de code, namelijk A en 1. Op zich hoeft dit nog geen + probleem te zijn, maar zodra we een bestand krijgen waarin + (bijna) geen opvolging van gelijke elementen zit, zal de + compressie niet goed werken, sterker nog, zal negatief gaan + werken. Het resultaat wordt namelijk groter dan het + orgineel. Gelukkig is hier een, niet zo moeilijke, oplossing + voor te vinden, waardoor runlength toch een redelijke + compressie-methode blijft. De volgende keer gaan we hier + echter verder op in. + + ---- VOLGENDE KEER ---- + + Volgende keer volmaken we dus het runlength-encoden en + behandelen het decoden. Ook maken we dan spelenderwijs een + runlength encoder-decoder om grafische schermen mee te + comprimeren. + + Jan-Willem van Helden + diff --git a/future_disk/17/pascal_6.md b/future_disk/17/pascal_6.md new file mode 100644 index 0000000..38ac574 --- /dev/null +++ b/future_disk/17/pascal_6.md @@ -0,0 +1,245 @@ + + PASCAL 6 + ======== + + + ���� Tja, vorige keer was ik er niet helemaal met mijn koppie + ���� bij, want ik heb een deel van wat ik moest vertellen + ���� vergeten(NvdR: de eikel!). Ik heb verteld dat je eigen + ���� types kunt maken, maar ��n van de belangrijkste types ben + ik vergeten. Ik ben namelijk het RECORD en de string + vergeten. Hierbij dan ook mijn excuses en de aanvullende + informatie. + + TYPE + + Over de string kan ik heel snel zijn. De string is een "PACKED + ARRAY[1..?] of char". Een PACKED ARRAY is een array waarvan de + lengte intern wordt bijgehouden. Iets wat bij een string + noodzakelijk is, anders geven programma's als: + + PROGRAM StringVoorbeeld; + + TYPE + Woord = PACKED ARRAY[1..10] OF char; + + VAR + A : Woord; + B : Woord; + + BEGIN (* StringVoorbeeld *) + A:='hallo'; + B:=A; + Writeln(A); + Writeln(B); + END. (* StringVoorbeeld *) + + Het bovenstaande programma lijkt goed (A:=B mag bij arrays, + zolang de arrays van het zelfde type en even groot zijn), maar + er zal twee keer het woord 'hallo' verschijnen, met daarachter + 5 ongewilde karakters (mocht het zo zijn dat het programma + niet al een foutmelding geeft bij de opdracht A:='hallo', + omdat dat niet voldoet aan de voorwaarde van dezelfde grote). + Bij een PACKED ARRAY zoekt de computer zelf uit hoe groot het + ARRAY is en lost alle genoemde problemen dus op. Bij een + aantal compilers is het mogelijk om een type te gebruiken dat + "string" heet. Genoemd type wordt gebruikt bij TYPE met + "woord = string[10]" of bij VAR met "A : string[10]". + + Dat ik RECORD's vergeten ben is veel erger, omdat daar nou juist + de meeste leuke dingen mee gedaan kunnen worden. Een klein + voorbeeldje: + + PROGRAM RecordVoorbeeld; + + TYPE + datum = RECORD + dag : 1..31; + maand : 1..12; + jaar : 0..5000; + END; + persoonsgegevens = RECORD + naam : string[30]; (* ik maak + gebruik van + het string + type *) + geboortedatum : datum; + END; + + VAR + persoon : persoonsgegevens; + + BEGIN (* RecordVoorbeeld *) + persoon.naam:='Jeroen Smael'; + persoon.geboortedatum.dag:=27; + persoon.geboortedatum.maand:=10; + persoon.geboortedatum.jaar:=1970; + END. (* RecordVoorbeeld *) + + Op deze manier kun je dus hele gegevens "bomen" aanleggen. Bij + de persoonsgegevens kun je ook nog het adres, de geboortestad, + etc., etc. toevoegen. Alles wat je maar wilt. Zoals je ziet + moet je wel, om bij de velden te komen een punt gebruiken. + Deze punt is vergelijkbaar met de \ van DOS (het scheidings- + teken van subdirectory's). Tevens zie je dat ik pas jarig ben + geweest, maar dat terzijde(NvdR: so?). + + Met genoemde velden zijn verder natuurlijk wel alle + bewerkingen mogelijk, zo zou de opdracht: + "persoon.geboortejaar:=persoon.geboortejaar+1" een geldige + opdracht zijn. + + Een hele bruikbare "opdracht" bij records is de CASE opdracht. + Deze maakt het mogelijk om een of meerdere veldnamen weg te + laten. Met gebruikmaking van de CASE opdracht zou het vorige + (hoofd)programma er als volgt hebben uitgezien: + + BEGIN (* RecordVoorbeeld *) + CASE Persoon OF + naam:='Jeroen Smael'; + geboortedatum.dag:=27; + geboortedatum.maand:=10; + geboortedatum.jaar:=1970; + END; + END. (* RecordVoorbeeld *) + + Hetzelfde (de CASE) kunnen we natuurlijk ook toepassen bij de + geboortedatum en dan ziet het (hoofd)programma er als volgt + uit: + + BEGIN (* RecordVoorbeeld *) + CASE Persoon OF + naam:='Jeroen Smael'; + CASE geboortedatum OF + dag:=27; + maand:=10; + jaar:=1970; + END; + END; + END. (* RecordVoorbeeld *) + + Zoals te zien spaart dit een heleboel tikken. Let er + natuurlijk wel op dat de CASE afgesloten wordt door een END + (anders krijg je een compiler fout). + + Files + + Het zou uiteraard ook leuk zijn als we met PASCAL toegang + zouden hebben tot de diskette. Gelukkig hebben de makers + daaraan gedacht en kan dat. Voor de beeldvorming zal ik + uitleggen hoe PASCAL een file "ziet". + + Een file is in PASCAL een lange keten gegevens. De gegevens + zitten (en zullen ten eeuwige dagen blijven zitten) in de + volgorde waarin ze zijn weggeschreven. Bij het werken met een + file schuift er een "window" over de file, waardoor altijd + maar ��n gegeven per keer "zichtbaar" is. Het genoemde window + heeft trouwens de onprettige eigenschap dat het alleen maar + vooruit kan schuiven. Ophalen en wegschrijven van waardes + gebeurt via het window. Het window is te bereiken met "File^" + (waar File de naam van de filevariabele is). Ik zal nu wat + opdrachten bespreken die mogelijk zijn met files, waarna nog + een voorbeeld programma volgt. Opdrachten zijn: + + RESET(File) + Opent een file zodat er in gelezen kan worden (zet het + window aan het begin van de file). + REWRITE(File) + Opent de file en maakt hem geschikt om in te schrijven + (file is nu leeg, ook al was hij dat niet!!). + GET(File) + Schuift het window een plaats op (de nieuwe waarde kan met + "Waarde:=File^" opgevraagd worden). + PUT(File) + Zet de waarde van het window in de file en schuift het + window een plaats op (de window waarde kan veranderd worden + met "File^:=Waarde"). + READ(File,Waarde) + Leest uit de file en plaats de gelezen waarde in "Waarde" + (geen geklooi meer met het window, hier gebeurt dat + allemaal automatisch). + READLN(File,Waarde) + Idem als READ, maar leest tevens tot het einde van de regel + (wordt gebruikt bij tekstfiles). + WRITE(File,Waarde) + Schrijft de waarde van "Waarde" in de file en schuift het + window door (ook hier geen geklooi meer met het window). + WRITELN(File,Waarde) + Idem als WRITE, maar plaatst tevens een EOLN (End OF LiNe) + teken in de file (wederom bij tekstfiles). + EOF(File) + Geeft de waarde TRUE als het einde van de file bereikt is + (EOF = End Of File). + EOLN(File) + Geeft de waarde TRUE als het einde van de regel bereikt is + (EOLN = End Of LiNe). + + Officieel zijn genoemde opdrachten alle opdrachten voor files, + maar de meeste compilers hebben nog twee extra opdrachten en + dat zijn: + + ASSIGN(File,"FileNaam") + Dit koppelt de "File" aan de "FileNaam". M.a.w. Als ik iets + in de file schrijf, dan komt dit op de schijf in de file + "FileNaam" te staan. Volgens de regels van PASCAL is dit + niet nodig, omdat de fysieke file (de file op schijf) + dezelfde naam krijgt als de variabele "File" heeft. Veel + compilers hebben echter een ASSIGN opdracht nodig, anders + gebeurt er niets (vaak niet eens een foutmelding en al + helemaal geen file). + CLOSE(File) + Dit moge wel duidelijk zijn. Hier wordt de file gesloten. + Deze opdracht zorgt ervoor dat de file ook voor DOS + gesloten wordt, zodat er niet een ge-opende file achter- + blijft als het programma stopt. Deze opdracht moet dus + alleen op het einde van het programma staan. Ook deze + opdracht is geen standaard, maar moet ook bij de meeste + compilers worden toegevoegd voor een goede werking. + + Zo, en dan nu een voorbeeldje: + + PROGRAM FileVoorbeeld; + + TYPE + FileType = FILE OF integer; (* FILE OF AnyType is + mogelijk *) + + VAR + FileVar : FileType; + Teller : integer; + + BEGIN (* FileVoorbeeld *) + ASSIGN(FileVar,"testfile.dat"); (* voor de zekerheid *) + REWRITE(FileVar); (* ik wil er iets + inschrijven *) + FOR Teller:=1 TO 5000 DO + Write(FileVar,Teller); (* dat doe ik hier *) + FOR Teller:=5000 DOWNTO 1 DO + Write(FileVar,Teller); (* en hier ook *) + RESET(FileVar); (* nu wil ik lezen uit + de file *) + WHILE NOT EOF(FileVar) DO + BEGIN + Read(FileVar,Teller); (* hier noem ik + expliciet de file *) + Write(Teller); (* hier niet, dus gaat + de output naar het + standaard uitvoerap- + paraat en dat is het + beeldscherm *) + END; + CLOSE(FileVar); (* voor de zekerheid *) + END. (* FileVoorbeeld *) + + Dit voorbeeld zou een heleboel duidelijk moeten maken. Alles + wat je nu nog moet doen is verder experimenteren. Probeer eens + een tekstfile te lezen en/of schrijven, dan kun je zien wat + EOLN precies doet. + De opdrachten GET en PUT worden weinig gebruikt, maar je kunt + eens kijken hoe ze precies werken (goed voor de beeldvorming). + + Zo, dat was het dan alweer voor deze keer. Groetjes van, + + Jeroen 'ik ben nog lang niet aan mijn EOF' Smael + + C YA @!! diff --git a/future_disk/18/data_compressie_3.md b/future_disk/18/data_compressie_3.md new file mode 100644 index 0000000..31e8245 --- /dev/null +++ b/future_disk/18/data_compressie_3.md @@ -0,0 +1,316 @@ +---- Data Compressie (3) ---- + + + ���� Zoals vorige keer beloofd, ga ik verder met het vol- + ���� maken van de RUNLENGTH-methode. Of we aan het voor- + ���� beeld toekomen hangt af van mijn beschikbare tijd en + ���� de beschikbare diskruimte (NvdR: Ja, schuif maar af!) + + Laten we nog eens het voorbeeld van vorige keer herhalen: + We hadden de data 'AAABBACCCDDDD'. Na de stappen van het + RUNLENGTH-algoritme te hebben gevolgd kwamen we tot de + conclusie dat de gecrunchte data 'A3B2A1C3D4' zou worden. + Als je het allemaal niet meer helemaal weet, lees het dan + nog eens na op FD #17. + + Zoals vorige keer al opgemerkt is het element 'A1' storend. + We slaan immers dit als 2 bytes op (een byte voor 'A' en een + byte voor het aantal keer dat ie voorkomt '1'), terwijl er + in het orgineel maar 1 byte voor die 'A' nodig was. + Als dit maar weinig voorkomt treedt er natuurlijk geen + probleem op, maar als dit heel vaak gebeurt, is je + compressie zeer inefficient. Zo is het mogelijk om een 2 + keer zo grote file als output te krijgen. + + Om dit op te lossen kunnen we een extra byte bij de + crunch-data nemen. + +Eeuh, wat ? + + Nou kijk; we gaan nu in ons algoritme opnemen dat een byte + aangeeft of er crunch-data achterstaan of dat het + data-element gewoon ongecodeerd is opgeslagen. We noemen + deze byte even "CMP-ON" (CoMPression-ON). Voor onze + pseudo-code houdt dat dit in: + + [0] TELLER = 1; + [1] LEES DATAELEMENT; + [2] {X} <- VOLGENDE DATAELEMENT IN BESTAND; + [3] IS DATAELEMENT GELIJK {X} ?; + + (JA: VERHOOG TELLER; + GA NAAR [2]; + ) + (NEE: + [4] IS TELLER > 3 ?; + (JA: STUUR "CMP-ON"-BYTE NAAR DE CODE; + STUUR DE WAARDE VAN HET DATAELEMENT + + AANTAL KEER VOORKOMEN NAAR DE CODE; + GA NAAR [0]; + ) + (NEE: STUUR TELLER * HET DATAELEMENT NAAR DE + CODE; + GA NAAR [0]; + ) + ) + + Zoals je ziet lijkt het geheel nog steeds op het oude + voorbeeld. Opvallend is het toevoegen van een extra routine, + n.l. [4]. Deze routine kijkt of de TELLER groter is dan 3. + +Waarom 3 ?? + + Logisch, laten we even ervan uitgaan dat we het aantal + opslaan in een byte, het aantal in een byte en dat de + "CMP-ON" ook een byte inneemt. Samen maken dit 3 bytes. Als + we nu een data-element hebben dat maar 1 of 2 keer voorkomt, + heeft het natuurlijk weinig zin om dit gecomprimeerd op te + slaan. Dit zou namelijk tot gevolg hebben dat de code 3* zo + groot zou worden als het origineel. Een nog slechtere + compressie dan "normale" RUNLENGHT al zou hebben. Vandaar + deze extra stap [4]. + + Oplettende en zeer intelligente lezers hebben al opgemerkt + dat het programma voor de "CMP-ON" ��n byte gebruikt. Wat + gebeurt er nu als de waarde van het data-element gelijk zou + zijn aan de waarde van "CMP-ON"? Voor zowel het encoden als + decoden zou dit niets uitmaken, als de TELLER > 3 zou zijn. + Dat werkt gewoon. Als de TELLER <=3 zou zijn zou het encoden + ook geen probleem opleveren. Het programma zet gewoon 1 of 2 + (of 3, ligt aan de realisatie van je algoritme) bytes met + de waarde van "CMP-ON" in de code. Echter bij het decoden + de hele heisa fout gaan lopen. Kijken we maar eens wat er + gebeurt: + + Stel onze code is dit: + + [CMP-ON], "A" , "CMP-ON","A","40" + \ \ \ + byte waarde "CMP-ON" \ frequentie + \ + ongecodeerde byte + + Pakken we dat eens uit: Eerst vindt de decoder een byte met + de waarde "CMP-ON". Helaas herkent de decoder deze niet als + zijnde een waarde maar leest nu dat dit betekent dat de + volgende 2 bytes bestaan uit eerst een data-element en + daarna het aantal keer dat dit element voorkomt. De decoder + plaatst dan in het geheugen "CMP-ON" * "A"-tekens, terwijl + bedoeld was om eerst een byte met waarde "CMP-ON", dan een + byte met waarde "A" en dan een reeks van 40 bytes met waarde + "A". De decoder zal dus weinig begrijpen van de data. + +Hoe lossen we dit op??? + + Simpel! In het algoritme moeten we als de TELLER lager is + dan 3 de clausule opnemen dat een byte met de waarde van + "CMP-ON" moet worden opgeslagen alsof de TELLER > 3. In + pseudo code is er dan de aanpassing: + + [1] TELLER = 1; + | | | | | | + [3] IS DATAELEMENT GELIJK {X} ?; + + (JA: VERHOOG TELLER; + GA NAAR [2]; + ) + (NEE: + [4] IS TELLER > 3 ?; + (JA: STUUR "CMP-ON"-BYTE NAAR DE CODE; + STUUR DE WAARDE VAN HET DATAELEMENT + + AANTAL KEER VOORKOMEN NAAR DE CODE; + GA NAAR [0]; + ) + (NEE: + [5] IS DATAELEMENT = "CMP-ON" ?; + (JA: GA NAAR DE AFHANDELING VOOR + TELLER > 3; + ) + (NEE: STUUR TELLER * HET DATAELEMENT + NAAR DE CODE; + GA NAAR [0]; + ) + ) + + + Nu werkt dus het gehele encoden en decoden goed, maar treedt + er nog steeds soms negatieve compressie op. Immers als je + net een aantal keer "CMP-ON" afgewisseld met andere bytes + tegenkomt in je data, dan slaat de encoder als deze + "CMP-ON"'s op als 3 bytes. + +LEES VERDER IN TEKST 2! + + ---- Data Compressie 3-2 ---- + + +....VERVOLG + + Het moge duidelijk zijn dat de waarde "CMP-ON" moet worden + toegekend aan een byte die weinig in onze data voorkomt. + Om dus maximale compressie uit RUNLENGHT te halen kunnen we + het beste gaan zoeken naar een byte die zo weinig mogelijk + voorkomt. Dit houdt in dat het begin van het programma een + beetje veranderd: + + [0] ZOEK MINST VOORKOMENDE WAARDE; + [1] etc. etc. + + Deze stap [0] bestaat ook weer uit een aantal stappen, die + we wat dieper belichten. Eigenlijk is dit gewoon een + algoritme om de minst voorkomende byte te zoeken, maar + aangezien ik helaas niks over de standaard-vormen van zulke + algoritmen heb kunnen vinden heb ik er zelf maar een + ontwikkeld. Het werkt wel, maar zal waarschijnlijk sneller + en beter kunnen. + Werken we stap [0] eens uit: + + [0] ZOEK MINST VOORKOMENDE WAARDE + ( + [1] BYTE-WAARDE = 0; + AANTAL = 0; + [2] LAATSTE DATA-ELEMENT?; + (JA: SLA BYTE-WAARDE EN AANTAL OP IN + FREQUENTIE-TABEL; + BYTE-WAARDE = BYTE-WAARDE + 1; + AANTAL = 0; + [3] BYTE-WAARDE = 0 ?; + (JA: FREQUENTIE TABEL = AF; + END; + ) + (NEE: GA NAAR [2]; + ) + ) + (NEE: + [4] LEES DATA-ELEMENT; + [5] IS DATA-ELEMENT = BYTEWAARDE; + (JA: AANTAL = AANTAL + 1; + GA NAAR [2]; + ) + (NEE: GA NAAR [2]; + ) + ) + ) + + Je ziet dat het algorithme iets omslachtig is en ver is + uitgewerkt, maar door dit uit te voeren hebben we een + frequentie-tabel. Vervolgens hebben we nog een routine nodig + die het minst voorkomende element eruit vist, dus: + + + ( + [1] FREQUENTIE = 0; + TABELPOINTER = FREQUENTIE-TABEL + [2] LEES AANTAL + [3] IS FREQUENTIE = AANTAL?; + (JA: "CMP-ON" = BYTE-WAARDE"; + RETURN; + ) + (NEE: TABELPOINTER = TABELPOINTER + 1; + [4] EINDE FREQUENTIE-TABEL?; + (JA: TABELPOINTER=FREQUENTIE-TABEL; + FREQUENTIE = FREQUENTIE + 1; + GA NAAR [2]; + ) + (NEE: GA NAAR [2]; + ) + ) + + Deze routine werkt ook heel simpel: Eerst zoeken we of er + een AANTAL is dat gelijk is aan FREQUENTIE = 0. Vinden we + dit, dan maken we "CMP-ON" gelijk aan de bijbehorende + BYTE-WAARDE. Vinden we in de gehele tabel geen enkel AANTAL + dat gelijk is aan FREQUENTIE, dan verhogen we de FREQUENTIE + 1 en zoeken we weer vanvoorafaan. Dit doen we net zolang + totdat we een kloppende waarde gevonden hebben. Deze + BYTE-WAARDE dan de minst voorkomende. + Voor de gehele routine houdt dit in: + + -- Complete Source -- + + [0] ZOEK MINST VOORKOMENDE WAARDE + /* Stel de frequentie tabel op */ + ( + [1] BYTE-WAARDE = 0; + AANTAL = 0; + [2] LAATSTE DATA-ELEMENT?; + (JA: SLA BYTE-WAARDE EN AANTAL OP IN + FREQUENTIE-TABEL; + BYTE-WAARDE = BYTE-WAARDE + 1; + AANTAL = 0; + [3] BYTE-WAARDE = 0 ?; + (JA: FREQUENTIE TABEL = AF; + END; + ) + (NEE: GA NAAR [2]; + ) + ) + (NEE: + [4] LEES DATA-ELEMENT; + [5] IS DATA-ELEMENT = BYTEWAARDE; + (JA: AANTAL = AANTAL + 1; + GA NAAR [2]; + ) + (NEE: GA NAAR [2]; + ) + ) + ) + /* Zoek naar minst voorkomende waarde */ + ( + [1] FREQUENTIE = 0; + TABELPOINTER = FREQUENTIE-TABEL + [2] LEES AANTAL + [3] IS FREQUENTIE = AANTAL?; + (JA: "CMP-ON" = BYTE-WAARDE"; + RETURN; + ) + (NEE: TABELPOINTER = TABELPOINTER + 1; + [4] EINDE FREQUENTIE-TABEL?; + (JA: TABELPOINTER=FREQUENTIE-TABEL; + FREQUENTIE = FREQUENTIE + 1; + GA NAAR [2]; + ) + (NEE: GA NAAR [2]; + ) + ) + + /* Begin het echte comprimeren */ + + [1] TELLER = 1; + [2] LEES DATAELEMENT; + [3] {X} <- VOLGENDE DATAELEMENT IN BESTAND; + [4] IS DATAELEMENT GELIJK {X} ?; + + (JA: VERHOOG TELLER; + GA NAAR [3]; + ) + (NEE: + [5] IS TELLER > 3 ?; + (JA: STUUR "CMP-ON"-BYTE NAAR DE CODE; + STUUR DE WAARDE VAN HET DATAELEMENT + + AANTAL KEER VOORKOMEN NAAR DE CODE; + GA NAAR [1]; + ) + (NEE: STUUR TELLER * HET DATAELEMENT NAAR DE + CODE; + GA NAAR [1]; + ) + ) + + -- Next Time: -- + + Zo, nu hebben we een geheel algoritme voor maximale + RUNLENGTH compressie. Het lijkt wat geknutseld, maar werkt + wel. Volgende keer maken we van dit algoritme een mooi + code-programma en als de tijd het toelaat, maken we een + begin met de LZW-methode om data te comprimeren. + + Jan-Willem van Helden + + p.s. Voor de al wat verder gevorderden onder ons, de + pseudo-code die ik gebruik, lijkt verdacht veel op de + hogere programmeer-talen. Daar is die dan ook van af- + geleid. Als je nu een beetje handig bent, kun je deze + routines zo omzetten naar C (+/++/+++) of PASCAL + omzetten. Wie weet besteed ik daar ook nog eens wat + textjes aan. diff --git a/future_disk/18/mooblaster_music_cursus.md b/future_disk/18/mooblaster_music_cursus.md new file mode 100644 index 0000000..b96c9c8 --- /dev/null +++ b/future_disk/18/mooblaster_music_cursus.md @@ -0,0 +1,204 @@ + MOONBLASTER MUSIC-CURSUS + + + Wat is dit nu weer??? Een cursus MoonBlaster op de + FutureDisk? Ja, inderdaad, je leest het goed; ik heb + inderdaad het snode plan opgevat om deze (en de volgende) + FutureDisks te teisteren met een soort muziekcursus. + + In het verleden zijn er in, op en tussen andere bladen nogal + wat muziekcursussen geweest, en het was mijn bedoeling om + van deze cursus ook iets interessants te maken, en jullie op + die manier het een en ander op muzikaal MSX-gebied te leren. + Zelf ben ik helemaal niet zo muzikaal, maar met wat proberen + kom je echt al een heel eind. Zo is het eigenlijk niet nodig + dat je noten kunt lezen (kan ik ook niet, but who cares) + maar dit is wel handig als je bijvoorbeeld bestaande muziek + wilt namaken. + + WHAT DO I NEED? + + Voor deze cursus heb je vrij weinig nodig, maar een + aantal dingen zijn toch wel vereist, namelijk: + + - MoonBlaster (of een soortgelijk muziekprogramma) + - Een muziekuitbreiding, liefst FM-Pac en/of Music Module + - Veel inspiratie + + Met deze 3 dingen, en natuurlijk een abonnement op de + FutureDisk(NvdR: het laatste geeft natuurlijk de basis!) + moet het toch mogelijk zijn om iets hoorbaars te maken. + Maar nu genoeg geluld; verder met de eigenlijke cursus. + + DE OPBOUW VAN EEN MUZIEKSTUK + + Grofweg zijn de meeste (MoonBlaster-) muziekstukken te + verdelen in een vijftal groepen: + +1. DRUMS +2. ACCOORDEN +3. BASS +4. MELODIE +5. "SPECIAL EFFECTS" + + Als een soort richtlijn kun je de volgende twee manieren van + opbouw onderscheiden: + +Opbouwmethode 1. +================ + + Channel 1: de eerste noot van een accoord + Channel 2: de tweede noot van een accoord + Channel 3: de derde noot van een accoord + Channel 4: de bass + Channel 5: de melodie + Channel 6: de melodie, ditmaal met een soort van echo-effect + Channel 7: zie Channel 1, maar met echo + Channel 8: zie Channel 2, maar met echo + Channel 9: zie Channel 3, maar met echo + + (Accoorden zijn meestal opgebouwd uit 3 noten, maar ook + accoorden van 2, 4 of zelfs nog meer noten zijn mogelijk !) + +Opbouwmethode 2. +================ + + Channel 1: vormt samen met kanaal 2 een soort van "pingel" + Channel 2: zie kanaal 1 + Channel 3: de eerste noot van een (tweestemmig) accoord + Channel 4: de tweede noot van een (tweestemmig) accoord + Channel 5: de bass + Channel 6: de melodie + Channel 7: naar keuze een herhaling van Channel 1 of 3 + Channel 8: naar keuze een herhaling van Channel 2 of 4 + Channel 9: zie Channel 6, maar met echo + + (Over hoe je een echo-effect krijgt of hoe je een pingel + maakt, daar kom ik op een andere FD nog op terug) + +ZIE VOOR VERVOLG IN TEKST 2 !!! + + MOONBLASTER MUSIC-CURSUS(2) + + + + HOE MAAK JE EEN ACCOORD + + Een accoord is meestal opgebouwd uit 3 noten met een + verschillende toonhoogte, maar omdat ook twee-stemmige + accoorden mogelijk zijn zal ik een soort schema geven + waarmee het mogelijk zou moeten zijn om goed-klinkende + accoorden te maken. + + Voor het schema is het misschien wel handig om te weten hoe + een toonladder in elkaar zit. Aangezien de meesten dit wel + weten hou ik het kort: + + C# D# F# G# A# C# D# F# G# + C D E F G A B C D E F G + + Hierboven zie je bijna twee octaven (een octaaf loopt van de + C tot de B) waarin je alle noten ziet die MoonBlaster + aankan. Om nu een accoord te maken kies je een noot, + bijvoorbeeld de A-5 (zo voer je het in MoonBlaster in, het + betekent niks anders dan dat er een A wordt gespeeld op + octaaf 5). Dit is de eerste noot van het accoord. Om nu de + tweede noot te krijgen kies je de noot die drie stappen van + de beginnoot verwijderd ligt, in dit geval dus C-6 + (namelijk van A-5 naar A#5 is een stap, van A#5 naar B-5 is + de tweede, en van B-5 naar C-6 de derde) + Voor de derde noot van het accoord ga je weer uit van de + beginnoot (A-5) en ga je ditmaal zeven stappen verder, + waarna je dus uitkomt op E-6. + + Je kunt echter ook allerlei verschillende variaties maken, + bijvoorbeeld A-5, C-6 en F-6 of A-5, B-5 en D-6. + + En dan nu het langverwachte schema: + + [X+3+7] of [X+4+7] + [X+5+8] of [X+5+9] + [X+3+8] of [X+3+9] + [X+4+8] of [X+4+9] + [X+1+5] of [X+1+6] + [X+2+5] of [X+2+6] + + Het is misschien een beetje onduidelijk, maar ik zal het + uitleggen: het aantal stappen dat volgt na de "of" is + alleen nodig om sommige accoorden goed te laten klinken, + deze stappen komen echter niet zo vaak voor, alleen bij + bepaalde noten (meestal de G of de E). Probeer het zelf + maar, en als het niet klinkt moet je dus de andere stap + hebben. De "X" staat overigens voor de beginnoot. Met zelf + wat experimenteren bereik je ook een hele hoop, en na een + tijdje kun je zelf zo een accoord maken zonder erbij na te + hoeven denken. + + Je kunt van de driestemmige accoorden van het bovenstaande + schema ook heel eenvoudig twee-stemmige accoorden maken door + gewoon een van de noten (meestal de laagste) weg te laten. + Hierbij heb je gelijk nog wat kanalen over voor andere leuke + dingen. + + Als je een MusicModule hebt dan kun je voor je accoorden ook + nog kanaal 7 t/m 9 gebruiken. Je kunt dit natuurlijk ook + voor andere dingen zoals een "pingel" gebruiken, maar uit de + praktijk blijkt dat je, als je deze kanalen inderdaad voor + de accoorden gebruikt je een mooiere achtergrond krijgt. + + +ECHO..... ECho.... echo...... + + Het maken van een echo-effect kan op de volgende manier: + als je bij een kanaal (of in dit geval: de kanalen) een echo + wil maken moet je zorgen dat je hier wel genoeg kanalen voor + vrij hebt. Als je een driestemmig accoord hebt (dat dus drie + kanalen in beslag neemt) moet je zorgen dat je voor de echo + net zoveel kanalen vrij hebt, in dit geval dus drie. + + Stap 1: Als je op kanaal 1, 2 en 3 het accoord hebt moet je + dit kopi�eren naar kanaal 7, 8 en 9 (of andere + kanalen) met het commando [CTRL] + [C]. MoonBlaster + vraagt je nu het te kopi�eren kanaal in te voeren, + in dit geval dus kanaal 1. Vervolgens moet je het + kanaal geven waarheen het gekopi�erd moet worden + (kanaal 7 in dit geval) en tenslotte wordt je + gevraagd het aantal ECHO-steps te geven (van 0-4). + Bij normale snelheid (tempo 19) kun je hier het + beste [2] intypen, bij lagere snelheid kun je + beter een lagere waarde invoeren, en bij hogere + snelheid (tempo 21 of hoger) kun je overwegen om + voor [3] of [4] te kiezen. + + Stap 2: Zet het volume op de kanalen waarheen je gekopi�erd + hebt iets zachter (bij FM-Pac ongeveer 2 stappen, + bij MusicModule ongeveer 10 stappen). + + Stap 3: Detune de kanalen waarheen je gekopi�erd hebt d.m.v. + [F10] of (in de editor zelf) met [T+Y] of [T-Y], + waarbij Y staat voor een getal van 1 t/m 3. Kies in + dit geval de waarde "1". + + Stap 4: Misschien overbodig om te vermelden: op het normale + en op het echo-kanaal moeten dezelfde instrumenten + staan. + + THE END + + Tja, aan de bovenstaande melding te zien heb ik alweer veel + te veel getypt, en daarom verwijs ik jullie nu maar door + naar de disk waar, als de diskruimte het toelaat, nog enkele + voorbeeldjes op staan. Ook vind je hier enkele variaties wat + betreft accoorden. Tot de volgende keer, dan ga ik het hebben + over de drums !! + + Voor suggesties, op- of aanmerkingen kun je terecht bij: + + Erasmusweg 7 + 9602 AB Hoogezand + + + 05980-27379 (na 19.00 u) + + + Jorrith - SOUNDWAVE - Schaap diff --git a/future_disk/18/pascal_7.md b/future_disk/18/pascal_7.md new file mode 100644 index 0000000..dba6f4e --- /dev/null +++ b/future_disk/18/pascal_7.md @@ -0,0 +1,148 @@ + PASCAL (7) + + + + ���� We zijn bijna aan het einde gekomen van een reeks PASCAL + ���� cursi. Er zijn nog maar twee onderwerpen die ik wil + ���� behandelen: POINTERS en RECURSIE. Pointers is een soort + ���� data-type in PASCAL en recursie is een soort + programmeermethode. Omdat beide onderwerpen interessant + en (mijns inziens) belangrijk voor een programmeur zijn + besteed ik per onderwerp twee teksten hieraan (zodoende kan + ik dus nog drie teksten en FD nummers vooruit). Ik begin dus + met pointers (les 1). + + Wat is het voordeel van een FILE ten opzichte van een ARRAY: + - oneindig (een file kan in principe oneindig lang zijn) + - flexibele grote (een file kan altijd langer of korter + gemaakt worden) + - weinig geheugen nodig (voor een file is bijna geen + geheugenruimte nodig, wel schijfruimte natuurlijk, maar + daar hebben we tegenwoordig genoeg van) + + Wat is het voordeel van een ARRAY ten opzichte van een FILE: + - snel(1) (ieder element kan onafhankelijk van de andere + opgevraagd worden, dus niet eerst de hele file de revue + laten passeren voordat het laatste element gebruikt kan + worden) +- snel(2) (alles staat in het geheugen en geheugen is v��l + sneller dan disk) +- gemakkelijk (makkelijk te programmeren, denk maar eens aan + een sorteer-algoritme voor files) + + Door genoemde voordelen te combineren zou men een super + gemakkelijk en snel data-type moeten kunnen krijgen. Men heeft + lang (eigenlijk niet, maar voor het verhaal staat dat wel + leuk) gedacht en is met pointers gekomen. Het had snel en + gemakkelijk moeten zijn. Het is snel, maar zeker NIET + gemakkelijk. Wat zijn pointers dan wel vraag je je af? + - snel (alles staat in het geheugen) + - oneindig (zolang er geheugen is kunnen er pointers + aangemaakt worden) +- flexibele grote (tijdens programma executie kunnen nieuwe + pointers aangemaakt worden) + + Je kunt je nu natuurlijk nog niets bij pointers voorstellen, + maar dat ga ik even veranderen. Wat is een pointer namelijk in + de computer (hoe werkt het)? Een pointer is (zoals de naam al + zegt) een wijzer(NvdR: grote meid!). Genoemde wijzer kan + wijzen naar niets of naar een data-element. Wijst het naar + niets, dan wijst hij naar NIL (gereserveerd woord), dat + (waarschijnlijk) het getal 0 is en dus geheugenruimte 0 is. + Wijst het naar een data-element dan is de pointer het adres + waar dat data-element gevonden kan worden. Dus als ik een + pointer A heb, dan kan de inhoud van A NIL zijn of + (bijvoorbeeld) #a084. NIL wil zeggen dat de pointer nergens + naar wijst en #a084 dat de pointer naar adres #a084 wijst. + Staat op adres #a084 het getal 10, dan wijst de pointer dus + het getal 10 aan. Grafisch wordt een en ander vaak als volgt + weergegeven: + + A + +-+ +----+ + | |--->| 10 | + +-+ +----+ + + Bovenstaand geval is als een pointer een byte (1 byte in het + geheugen) aanwijst. Er zijn dus wel 3 bytes nodig om een en + ander goed te laten werken (2 voor de pointer (16 bits adres) + en 1 voor het data-element (byte)). Een pointer kan elk data- + type aanwijzen dat de gebruiker maakt, hierdoor is het + mogelijk om een zogenoemde gelinkte lijst te maken (een + pointer die naar een pointer wijst die naar een pointer wijst + die naar een pointer wijst die naar een pointer wijst die naar + een pointer wijst die naar een pointer wijst die naar een + pointer wijst die naar een pointer wijst die naar een pointer + wijst ...............). Op zich heb je daar dus niets aan, + maar als je alle pointers nu eens naar een RECORD laat wijzen + dat een data-element EN een pointer bevat, dan kom je al een + heel eind. Grafisch ziet dat er als volgt uit: + + Hoofd + +-+ +---+-+ +---+-+ +---+-+ +---+-+ +---+-----+ + | |--->| 5 | |--->| 9 | |--->| 4 | |--->| 0 | |--->| 1 | NIL | + +-+ +---+-+ +---+-+ +---+-+ +---+-+ +---+-----+ + + Allemaal heel leuk, maar hoe gebruik je dit (oftewel geef een + programma, dan zien we tenminste iets). Kijk maar eens naar de + file "POINTER.PAS" op deze diskette, daar staat een voorbeeld + in. + + Bij TYPE staat de declaratie van een pointer: + typenaam1 = ^typenaam2 (* ^ staat voor 'pointer naar' *) + + Hier is dus wel iets geks aan de hand, want Wijs is een + pointer naar Element, maar Element is nog niet bekent...... + MAG DAT???? Ja, dat mag, als uitzondering. Zouden we Element + en Wijs in de declaratie omdraaien, dan zouden we namelijk een + soortgelijk probleem hebben omdat in Element, Next van het + type Wijs is. Bij pointers mag er dus een type vooruit genoemd + worden. Overigens wel in de volgorde zoals in het voorbeeld + staat (dus eerst het pointer-type en daarna pas het type waar + de pointer naar wijst). + + De variabele declaratie zal geen problemen opleveren, dit in + tegenstelling tot het hoofdprogramma. Het eerste nieuwe dat we + tegenkomen is 'Hoofd:=NIL'. Aangezien Hoofd nog een + ongedefinieerde waarde heeft, maken we deze eerst gedefinieerd + (vanaf nu wijst Hoofd dus nergens naar). Het volgende is + 'NEW(Hulp)'. Hier wordt een geheugenplaats aangevraagd voor + het data-type van Hulp. (voor de opdracht NEW wijst de pointer + Hulp naar een ongedefinieerde plaats in het geheugen. Bij de + NEW opdracht wordt er in het geheugen gezocht naar een plaats + waar het data-type van de pointer inpast (in dit geval een + integer en een pointer)). Deze geheugenruimte wordt dan + gereserveerd voor zulk een data-type en de pointer wijst vanaf + nu naar genoemde plaats in het geheugen). + + De toekenningsopdrachten zijn min of meer vanzelfsprekend als + je weet dat pointer^ het data-element is (dus Hoofd^ is een + RECORD met twee velden (Waarde en Next), de inhoud van Waarde + is dus te bereiken met Hoofd^.Waarde). Wel moet ik vermelden + dat als je een pointer (bijvoorbeeld Hulp) zelf veranderd, dat + de computer dan niet de geheugenruimte vrijmaakt waar de + pointer naar wijst. Door alsmaar 'NEW(hulp)' als opdracht te + geven zou het geheugen dus vollopen (zorg ervoor dat je het + adres van het data-element ergens bewaart, anders ben je het + voorgoed KWIJT in het walhalla van je computer geheugen). In + het voorbeeld programma raak ik niets kwijt (ook visueel + zichtbaar) omdat ik een gelinkte lijst maak (ik laat de + elementen naar elkaar wijzen). + + Wil je de geheugenplaats waar een pointer naar wijst vrij + maken dan gebruik je DISPOSE (zoals ook op het einde van het + programma te zien is). + + Zo, dat was het dan alweer. Volgende keer meer, veel meer over + pointers, maar voor nu 2 opdrachten om jezelf te testen: + + (1) Zie voorbeeld programma, maar nu de getallen in volgorde + van invoer in de lijst plaatsen. + (2) Zie voorbeeld programma, maar nu de getallen gesorteerd in + de lijst plaatsen. + + Veel plezier, + + Jeroen 'Pointer to FD' Smael + + (NvdR: 'Pointer to Smael: ^Shut up!) diff --git a/future_disk/18/undocumented_z80_code.md b/future_disk/18/undocumented_z80_code.md new file mode 100644 index 0000000..67df4ff --- /dev/null +++ b/future_disk/18/undocumented_z80_code.md @@ -0,0 +1,57 @@ + -- MCODE -- + + + ���� + ���� + ���� + ���� + ���� + + Stop de persen, gooit uw PC uit het raam, speelt uw MOD's op + via uw Simpl, schrijf u in voor een survival-tocht in + Grozny, omhels S.B. en wordt lid van de EO. Wat is immers + het geval? + + Sinds ik mijn tijd verdoe op de TU in Eindhoven, leer je + allerlei dingen over computers en kom je andere MSX-ers + tegen. Zo hoorde ik laatst van Zelly (wie dat is zoek je + zelf maar uit) dat er alweer een ongedocumenteerde + instructie van de Z80 bestaat: + + IN F,(C) + + Huh, was dat niet een R800-commando?? In m'n Z80? + Jawel hoor, die klojo's van Zilog hebben ons al bijna 20 + jaar instructies verzwegen (durven ze wel stelletje boeren). + Een daarvan is dus deze. Je bereikt hem door in WBASS-2 in + de editor het volgende te zetten: + + IN (HL),(C) + + Als opcode houdt dit in: EDh,70h. En verdomt, zo staat ie + ook gedocumenteerdt in de R800-manual. + Intern doet de Z80 eigenlijk de volgende dinges: + + IN A,(C) + OR A + + Zo zou deze opcode dan ook kunnen maken, ware het niet dat + IN F,(C) register A ongeschonden houdt. + + Wat kan ik nu met deze instructie ??? + + Wel, je kunt er heel gemakkelijk een I/O poort mee in de + gaten houden en hoeft geen OR-ren of AND-en meer te + gebruiken. Kortom sommige dingen kunnen sneller! + + Programmeurs van Nederland, omhels deze instructie en + waardeer hem alsof hij er altijd al was. Schroom je niet om + 'm te gebruiken. Hij is eindelijk legaal verklaart !!! + + Veel plezier met deze instructie, + + Digital JW + + p.s. Er hebben mij geruchten bereikt dat de Z80 ook zou + kunnen vermenigvuldigen. Laten we dat eens gauw uit- + proberen... diff --git a/future_disk/19/basic_cursus_8.md b/future_disk/19/basic_cursus_8.md new file mode 100644 index 0000000..3d5c071 --- /dev/null +++ b/future_disk/19/basic_cursus_8.md @@ -0,0 +1,77 @@ + Basic Cursus (7) + + + ���� + ���� + ���� + ���� + + OUT&HFE en ander ge-emmer + + In Basic heeft de gebruiker eigenlijk maar weinig geheugen + tot zijn beschikking. &H0000-&H7FFF is immers Rom, + op &H8000-&HBFFF staat je basic programma, en alles boven + &HE000 is eigenlijk ook al linke soep... Blijft dus over + &HC000-&HE000, en das nie bar veel! In die 8Kb kun je + natuurlijk wel een zooitje strings en variabelen kwijt maar + als je ook maar iets bv op sector in wil laden of een + aantal sampletjes wil afspelen dan zit je al in de knoop. + Een redelijk onbekende -onbeminde- methode is om basic + gewoon op C000 te flikkeren en daardoor komen alle banks + van 8000-BFFF weer vrij. For the ignorant, a little scheme: + + I Geheugen I Vrije Banks I + -------------------------- + I 64Kb I 1-3 I + I 128Kb I 1-7 I + I 256Kb I 1-15 I + I 512Kb I 1-31 I and so on..... + -------------------------- + + Als je dit geintje dus uitvoert heb je in ��n keer een hele + zwik geheugen tot je beschikking, wat overigens heerlijk is. + Dit truukje werkt echter alleen met de interne of op de op + dat moment ingeschakelde mapper. Twee mappers in basic + gebruiken kan wel maar dat ga ik niet helemaal uitleggen. + Eerst zul je dus Basic op $C000 moeten zetten, daarna moet + je natuurlijk nog weten hoe je welke mapper bank in moet + schakelen. Mapper bank0 is niet beschikbaar, dit is normaal + gesproken &HC000-&HFFFF waar Basic z'n administratie neerzet + en de gebruiker nog even rond kan poken/peeken. Mapper bank + 1 wordt door Basic gebruikt om de programma-data in op te + slaan, hier staat dus normaal je programmaatje in. Nu gaan + we dat programmaatje naar &HC000 verplaatsen. Theoretish + mag dat niet omdat je dan in de knoop kan komen met je + systeem variabelen die Basic in die bank opslaat. In de + praktijk valt dit over het algemeen wel mee. 't Is mij + in iedergeval nog nooit gelukt. Dit betekent namelijk een + listing die Tokenized al meer dan 8Kb zou zijn. Grote jongen + die dat bij elkaar typt! Nu is bank1 dus ook vrijgekomen + aangezien je programmaatje daar nu niet meer staat. Je kunt + dus -behalve bank0- alle banks gebruiken (Zie schema). Dan + nu 't eigenlijke programmaatje wat je dan krijgt: + + 10 ' MEMTEST.BAS + 20 IFPEEK(&HF677)<>&HC0THENPOKE&HF677,&HC0:POKE&HC000,0: + RUN"MEMTEST.BAS" + 30 FORP=1TO255:OUT&HFE,P:POKE&H8000,55:NEXTP + 40 FORP=1TO255:OUT&HFE,P:IFPEEK(&H8000)=55THENPG=PG+1:NEXTP + 50 PG=PG+1:PRINT PG*16;"KB GEHEUGEN" + + Nu is dit maar een stom programmatje maar wat je nu feitelijk + met die pages doet boeit eigenlijk niet. Pleur d'r maar eens + graphics of muziek neer. Samples wil trouwens ook prima. Als + je 't echt netjes wil doen pleur je alles wel weer keurig + terug als je klaar bent. Dus krijg je: + + 60 POKE &HF677,&H80:POKE&H8000,0 + + Als je daarna namelijk andere programma's gaat laden die er + niet op rekenen dat basic op $C000 staat wil dat nog wel + eens de soep in lopen. Het is overigens ook wijsheid om + met CTRL op te starten aangezien basic dan wat minder + geheugen nodig heeft voor z'n drive administratie. + + Well that's all, bye.... + + Tobias 'I love my 512Kb mapper' Keizer diff --git a/future_disk/19/basic_voor_beginners.md b/future_disk/19/basic_voor_beginners.md new file mode 100644 index 0000000..395955d --- /dev/null +++ b/future_disk/19/basic_voor_beginners.md @@ -0,0 +1,89 @@ + BASIC CURSUS + + algemene hints voor beginners + + + ���� + ���� + ���� + ���� + + + Ja, even voor de al iets verder gevorderden onder u. Deze keer + staat er eigenlijk niets in voor jullie dus, err, why don't + you go tie your dick in a knot?!(NvdR: ik zal je maar niet + de 993 redenen noemen) + + Even een aaqntal tips voor de beginnertjes. Gezien 't feit dat + de basic interpreter uit ons lieve MSX-je nog langzamer is dan + mijn oma van 94 moet je erg opletten met wat je doet in je + programmaatje. Let hierbij vooral op loops omdat deze vaker + worden uitgevoerd. Eerst dus even een paar DO's en DONT's. + + Vermijd REM of ' in een loop omdat deze vreemd genoeg tijd in + nemen. Je zou haast verwachten dat basic gewoon door gaat na + het tegenkomen van een REM of ' maar hij loopt vreemd genoeg + eerst de hele regel door. Nadat je dus je REM's keurig voor of + na de loop heb gezet ga ik je opeens vertellen dat je het ' + tekentje eigenlijk maar niet moet gebruiken omdat deze vreemd + genoeg 3 bytes inneemt terwijl het drie letters tellende woord + REM maar 1 byte inneemt. Nu gebruik ik zelf gewoon altijd ' + maar mocht je dus ooit in geheugen probleemples komen kun je + altijd nog je '-tjes vervangen door REM's. Maar het best vind + ik nog altijd helemaal geen REM's of '-tjes. + + Spaties zijn ook een probleem, deze kosten namelijk tijd. + Ik persoonlijk typ gewoon geen spaties in m'n basic werk maar + wat ook prima werkt is eerst typen en later als alles af + is(�n werkt) de spaties er uit halen. Pas wel op: soms zijn + spaties verplicht om alles nog goed te laten werken. + + Wisselen tussen twee waarden. + Ook dit kost nog wel eens tijd. Vaak krijg je allerlei IF THEN + constucties in je programmaatje die niet al te snel zijn. + Kijk altijd eerst of 't een en ander niet met een XOR te + verhelpen is. XOR's zijn namelijk heel snel. Als je dus bv + wisselen moet tussen 2 en 0 wat bv bij het veranderen van + de frequentie nog wel eens 't geval is, krijg je meestal + iets als: + + 10 ' 0 = 60Hz 2 = 50Hz + 20 IF HZ = 0 THEN VDP(10)=2 : HZ=2 : GOTO 40 + 30 IF HZ = 2 THEN VDP(10)=0 : HZ=0 : GOTO 40 + 40 BLA BLA BLA.... + + Veel sneller is + + 10 ' 0 = 60Hz 2 = 50Hz + 20 HZ=HZ XOR 2 : VDP(10)=HZ + + Of nog sneller (en technisch gezien de enige goede manier) + + 10 VDP(10)=VDP(10)XOR2 + + Even voor die mensen die niet weten wat een XOR doet: + een XOR doet niets anders dan het (de) aan gegeven bit(s) van + een byte omgooien. Als (zoals bij 't voorbeeld) de byte dus + &B00000010 is en de XOR &B00000010 is wordt bit twee dus ook + steeds omgegooid. Mensen die niet weten hoe 't binaire stelsel + in elkaar steekt raad ik aan eens hun BASIC manual door te + lezen waar dit soort dingen vaak wel instaan. Hierbij raad ik + aan het gedeelte over het octale stelsel over te slaan aan- + gezien dit eigenlijk nooit wordt gebruikt in BASIC(NvdR: in + andere talen ook vrijwel niet heb ik me laten vertellen door + Jan-Willem!). + + Voor jullie beginners raad ik dus aan eens goed met die XOR's + en andere operaties in BASIC te gaan spelen want het scheelt + echt wel als je die goed onder de knie heb. + Lieden die echter denken dat het nodig is om uit het hoofd de + getallen van 0 tot 255 van DEC naar HEX en van HEX naar BIN + te kunnen omrekenen hebben wel een erg hoog doel en kunnen + maar beter door gaan met de MC cursus elders op dit mag. + Toegegeven, 't is wel handig om sommmige waarden in HEX, + DEC en BIN uit 't hoofd te kennen. + + Well boys, that's about it for now. + Read the rest of my shit in the next txt-file. + +Tobias 'kill that space' Keizer diff --git a/future_disk/19/looplichtjes_2.md b/future_disk/19/looplichtjes_2.md new file mode 100644 index 0000000..a369bb8 --- /dev/null +++ b/future_disk/19/looplichtjes_2.md @@ -0,0 +1,39 @@ + LOOPLICHTJES + + ���� + ���� + ���� + ���� + + Enige tijd geleden, FD #15 om precies te zijn, plaatste ik een + artikeltje over looplichtjes met daarbij een schemaatje om 't + zooitje te bouwen. Ik beloofde daarbij ook een programmaatje + om de aansturing wat makkelijker te maken. Welnu, van dat + programmaatje is nooit al te veel gekomen wegens tijdgebrek + maar een aantal bellers meende dat 't zonder dat + programmaatje niet mogelijk was om 't looplichtje aan te + sturen. Dit is echter niet het geval. Op FD #15 stond namelijk + een programma dat naar de naam 'LOOPLICH.BAS' luisterde. Met + dit programma was 't wel degelijk mogelijk om het looplichtje + aan te sturen. Dat verklaart hopelijk 't ��n en ander en het + is dus ook niet zo dat ik de lezers van de FD compleet + belazer. Aansturen was wel degelijk mogelijk, ook in de tijd + van FD #15 al. Ik heb nu nogmaals het programma op de + disk laten zetten en ik hoop dat het eventuele misverstand + uit de lucht is geholpen. In het vervolg raad ik leden van + de FD dan ook aan om bij problemen niet contact op te nemen + met de redactie maar met mij persoonlijk aangezien ik zelf + meer verstand heb van mijn eigen brouwsels dan onze + -onkundige- redactie. Bij deze dan nogmaals mijn adres en + telefoonnummer en miscchien dat mijn telefoonnummer + ook door de redactie kan worden opgenomen bij de helplines + aangezien ik nooit te beroerd ben om de mede MSXer te helpen. + (NvDR: je bent te goed voor deze wereld, Keizer!) + + Tobias Keizer + Oudestraat 21-2 + 8261 CC Kampen + Tel: 05202-31348 + Fax: 05202-31348 + + Tobias 'Light Emiting Brain' Keizer diff --git a/future_disk/19/mcode_special_1.md b/future_disk/19/mcode_special_1.md new file mode 100644 index 0000000..915d470 --- /dev/null +++ b/future_disk/19/mcode_special_1.md @@ -0,0 +1,181 @@ + + MCODE SPECIAL(1) + + + Welkom bij deze speciale aflevering van de programmeercursus. + Dit keer geen gezwam over Z-80 instructies, maar de komplete + uitleg over hoe een spel in machinetaal geprogrammeerd wordt. + Hierbij wordt aangenomen dat je de vorige afleveringen van + deze programmmeercursus allemaal gevolgd hebt, dan wel + zelf kennis hebt opgedaan over de Z-80 instructies en het + gebruik daarvan in machinetaal programma's. + Ik zal een poging doen om zoveeeeel uitleg te geven dat + iedereen, die interesse heeft deze tekst kan volgen. Mocht + het een of andere nog niet duideljik zijn: mijn + telefoonnummer is 04746-1655 (voor 7 uur ben ik normaal niet + thuis). + Als voorbeeld van een spel wordt het bekende spel + MINE-SWEEPER genomen, aangezien de omvang van de routines + van dit spel niet zo groot is, maar er toch erg veel van + geleerd kan worden over spelprogrammeren. + Alvorens verder te lezen raad ik je aan het spel eerst + zelf een paar keer te spelen en voor jezelf al een beeld + te vormen hoe je een en andere zou programmeren. Voor de + mensen met printer: het kan erg handig zijn om de listing + van het spel op papier te hebben om ze erbij te kunnen + houden terwijl je deze tekst leest(NvdR: staat op de disk + onder de filenaam MINESW.GEN.) + + Hier volgt eerst een korte beschrijving en uitleg van het + spel voor degenen die het spel niet kennen. + Het is de bedoeling om alle mijnen in het mijnenveld, + voorgesteld door een scherm met vierkantjes, te vinden en + op veilig te stellen. + Met de muis of de cursortoetsen kan een pijltje bestuurd + worden en met een druk op de spatiebalk of linkerknop kan + gekeken worden of zich onder een vierkantje + (=hokje/blokje/veld) een mijn bevindt of niet. + Bevindt zich geen mijn op de plaats waar gedrukt werd wordt + in het hokje een cijfer afgebeeld dat aangeeft hoeveel + mijnen zich rondom het blokje bevinden. Een leeg hokje + betekent dus geen mijnen op de 8 aangrenzende plaatsen; dit + moet er toe leiden dat alle 8 aangrenzende hokjes automatisch + zichtbaar gemaakt worden (totdat er geen omliggende hokjes + meer leeg zijn!). + Wordt op een mijn gedrukt betekent dit automatisch het + einde van het spel, alle mijnen worden dan nog even + zichtbaar gemaakt. + Met een druk op SHIFT of de tweede muisknop kan een hokje + op veilig gesteld worden hetgeen m.b.v. een vlag aangegeven + wordt. + Zijn alle mijnen op veilig gesteld en alle niet mijnen + zichtbaar gemaakt dan is het spel gewonnen (tevens ten + einde). + + We hebben om dit spel te programmeren dus (hoofdzakelijk) + nodig: + + 0. Een routine, die het nodige initialisatiewerk doet. + 1. Een muisroutine/cursorroutine, die een pijltje (een sprite) + over het scherm kan bewegen. + 2. Een routine die de 1e muisknop/spatiebalk uitleest en kijkt + of er op de coordinaten waar het pijltje zich nu bevindt + een mijn bevindt + 2a. zo ja, het hele veld zichtbaar gemaakt wordt + 2b. zo nee, uitzoekt hoeveel mijnen rondom zitten en dit + nummer afdrukt of + 2c. als er geen mijnen rondom zijn de onliggende hokjes + automatische zichtbaar maakt tot er geen lege omliggende + hokjes meer zijn. + 3. Een routine, die uitzoekt hoeveel hokjes nog zichtbaar + gemaakt moeten worden voor het spel gewonnen is/ + 4. Een routine, die de SHIFT-toets en tweede muisknop + uitleest en hokjes op veilig kan stellen/weer onveilig + kan maken. + + + STARTEN + + Uitgegaan wordt van 1 programma, geschreven in machinetaal, + m.b.v. TED of GEN80. + Besloten wordt nu eerst het spel in Screen 5 te gaan maken, + voor het pijltje een sprite te kiezen en de rest van de + grafische commando's op te lossen met COPY's. + M.b.v. Spen wordt op de eerder beschreven methode (machinetaal + cursus zoveel) een pijl getekend als dubbele sprite + (dus 2 sprites over elkaar heen, om meer kleuren te kunnen + gebruiken) en de DATA naar TED gehaald (zie labels SPRCOL en + SPRPAT). + Besloten wordt het scherm op te delen in 16x16 blokjes, die + de mijnenvelden voorstellen. OP het scherm passen dan + 256:6=16 blokjes in x richting en 212:16=13.25 --> 13 blokjes + in vertikale richting. In DD-Graph worden nu eerst de + benodigde 16x16 symbolen getekend, die we in het spel nodig + hebben(in volgorde zoals ze op de page staan): + +xco 0 16 32 48 64 80 96 112 128 144 160 176 + Leeg H.,1, 2, 3, 4, 5, 6, 7, 8, Onzichtbaar H.,Vlag,Mijn + + (H. = hokje) + + Besloten wordt op deze blokjes op Page 1 neer te zetten op + Yco 0. + (xco=x-coordinaat en yco=y-coordinaat). + Het spel zelf zal zich gaan afspelen op Page 0. + In DD-Graph wordt het gebruikt palet tevens omgezet naar + DATA, die we in het hoofdprogramma kunnen gebruiken (zie het + label:PALET). + + In een Basic-programmatje (n.l. "MINESW.BAS") worden deze + blokjes m.b.v. een Copy commando op de juiste plaats gezet + en dit programma start tevens het hoofdprogramma "MINESW.COM" + op. + + We kunnen nu eindelijk beginnen met het echte werk: het + hoofdprogramma + + + HET HOOFDPROGRAMMA + ("MINESW.GEN") + ------------------ + +Initialisatie + + Er wordt gebruik gemaakt van het lijstje met benodigheden voor + het spel en we beginnen dus uiteraard met het + initialisatiewerk. Omdat we het programma vanuit basic willen + kunnen opstarten m.b.v. BLOAD (en GEN80 slechts .COM-files + maakt voor op te starten vanuit DOS) komt nu eerst een HEADER: + + DB #FE ; geeft aan dat dit een "BLOAD-file" is + DW ST ; startadres + DW EN ; eindadres + DW ST ; beginadres + + Bovendien wordt aan een aantal BIOS-adressen een naampje + gegeven, zodat we later in het programma CALL GTTIG (=get + trigger) kunnen gebruiken i.p.v. een onduidelijke CALL #D8. + + Initialisatie van de sprites gebeurt in de subrotine INIT, + omdat het onhandig is later telkens de lange initialisatie- + routines te moeten overslaan, terwijl je iets in het + hoodfprogramma wilt veranderen. In deze routine, worden de + spritekleuren en patronen in het videogeheugen opgeslagen, + de sprites "aan"-gezet en op 16x16 formaat. + Het besturen van een sprite komt nu er op neer dat je de + coordinaten in de spriteattribuutgeheugen veranderd + (label:SPRATT). + Merk op dat deze INIT afsluit met een routine SETSPRITES, + die de sprites de eerste keer neerzet, maar die later + opnieuw aangeroepen kan worden als er sprites bewogen + worden! + De routine wordt aangeroepen met CALL, hetgeen betekent + dat er na een RET terug gesprongen wordt naar het + aanroeppunt. De routine sluit echter af met een JP naar + een biosadres, waar automatisch een RET gevonden wordt + m.a.w.: + + CALL+RET=JP + + Voor verdere uitleg over sprites : zie de eerder verschenen + FUTUREDISK met de cursus over sprites. + + Nadat de sprites zijn geinitialiseerd wordt het Palet + aangezet, door in HL het adres van de paletgegevens + (uit DD-Graph) te zetten en de subroutine SETPAL aan te + roepen. Verder uitleg over SETPAL voert hier te ver aangezien + dat meer in een VDP-cursus thuishoort. Neem maar van mij aan + dat de routine werkt en je hem zonder problemen in je eigen + programma kunt gebruiken. + + Programmeertechnisch gezien kun je nu het beste verder + gaan met de besturing van de pijl, maar om even de lijn van + het programma te blijven volgen komen we nu uit in de + routine VULSCHERM, die het hele scherm vult met blokjes. + Alvorens ik de werking van VULSCHERM uit de doeken doe is + het nodig iets meer te praten op de opslag van de gegevens + over de mijnen. + + MAAR HELAAS DOEN WE DAT PAS DE VOLGENDE KEER! TOT DAN! + + Ruud Gelissen diff --git a/future_disk/19/moonblaster_music_cursus_2.md b/future_disk/19/moonblaster_music_cursus_2.md new file mode 100644 index 0000000..29a53f0 --- /dev/null +++ b/future_disk/19/moonblaster_music_cursus_2.md @@ -0,0 +1,90 @@ + MOONBLASTER CURSUS (2) + + + + Zoals iedereen (is d'r wel een hond die dit leest?)(NvdR: ja, + ikke!) de vorige keer al heeft kunnen lezen, zou ik deze keer + de drums bespreken. Dus niet; wegens tijdsgebrek ben ik er + niet aan toe gekomen, zelfs de muziek van deze FD is niet + meer dan minimaal.... Zo zie je maar weer, het leven van een + FD-redactielid gaat niet over rozen. Om de musiccorner toch + te kunnen vullen (en omdat ik toch nog een opmerking kreeg + dat ik de accoorden niet op de beste manier had uitgelegd, + maar daarover straks meer) ga ik het alweer hebben over de + accoorden. Degene die nu met de slimme (?) opmerking komt in + de geest van "Hee, dit lijkt de muziekcursus op de GPD wel" + (dat was waarschijnlijk 1 persoon (ene S.B. uit W., een + nogal beruchte MSXer die iets met Econometrie ofzo aan het + doen is)) moet het dan maar overnemen (dan heb ik tenminste + de tijd om de muziek eindelijk eens goed te maken...). + + NOGMAALS DE ACCOORDEN + + Ik heb op de vorige aflevering van de cursus wel van ��n + (NvdR: waauw dat is veel) persoon commentaar gehad, namelijk + van Stefan Boer, het opperhoofd van de stam der reizende en + rijzende zonnen. + Hij beweerde dat het allemaal eenvoudiger kon, en zou mij + dus een tekst hierover sturen die ik tot op heden nog niet + ontvangen heb (ja, dit is inderdaad een hint!). + Omdat ik de helft niet meer zo goed weet moet ik het maar + ongeveer uit m'n hoofd stampen, dus het zal wel niet + helemaal kloppen. + + Stel je maar eens een klavier voor, en ga bij het + onderstaande uit van de witte toetsen. + Je kiest een beginnoot (bv. C), je slaat een toets over, en + neemt de daarop volgende toets (in ons voorbeeld dus de E). + Doe ditzelfde ook voor de laatste noot van het + (driestemmige) accoord (de G), en je krijgt het volgende + accoord: C E G + + Volgens Stefan werkt dit zo met alle witte toetsen. Als je + goed luistert zul je merken dat er steeds hetzelfde verschil + in toonhoogte inzit (gek h�?), en hiermee kun je dus, als je + op het gehoor afgaat, ook zo een accoord met de zwarte + toetsen maken. De andere variaties uit de vorige cursus + krijg je geloof ik door de hoogste noot van het accoord een + octaaf te verlagen. Meer kan ik er momenteel eigenlijk niet + over zeggen, het wachten is op de beloofde tekst. Ik kom er + hoogstwaarschijnlijk nog wel op terug..... + +SOMETHING COMPLETELY DIFFERENT + + Om dit deel toch vol te krijgen kan ik nog wel iets + vertellen over de OPL-4 van Yamaha. De mogelijkheden zijn al + eens beschreven door Tobias "shit for brains", en hier zal + ik dus ook niet meer op ingaan. + De produktie van de MoonSound is aardig in de war gelopen. + De chips van Yamaha werden pas half februari verstuurd, dus + op zich zou het niet al te lang meer moeten duren, ware het + niet dat er een verkeerd onderdeel is besteld, waardoor de + eerste �cht werkende MoonSounds pas op de beurs in Tilburg + geleverd worden. De volgende series MoonSound en Graphics + 9000 worden waarschijnlijk een paar tientjes duurder. + Overigens krijg je bij deze twee produkten wel al kabels + meegeleverd. + De MoonSound komt - als het even meezit - wel in een + cartridge te zitten, met de V9990 is dit niet het geval. + Deze insteekkaarten zijn te groot om met een behuizing in + een cartridgeslot te passen, en daarom kun je je Graphics + 9000 in een metalen kastje laten bouwen voor Fl. 35,- (Dit + lijkt wel een STER-spotje voor Sunrise...) + Van MoonSound kun je waarschijnlijk nog wel binnenkort een + bespreking op de FD lezen... + + I'M GONNA LEAVE YOU + + Dit was het voor deze keer, mijn tijd is beperkt, en mijn + werk juist niet. Voor de volgende keer hopelijk een betere + en langere aflevering, met waarschijnlijk het laatste deel + van de accoorden en als nieuwe onderwerpen de drums en de + bassline.... + Cya !! + + Jorrith "slaapkop" Schaap + Erasmusweg 7 + 9602 AB Hoogezand + + + Tel: 05980-27379 diff --git a/future_disk/19/msx2+_schermen_in_basic.md b/future_disk/19/msx2+_schermen_in_basic.md new file mode 100644 index 0000000..ce716e0 --- /dev/null +++ b/future_disk/19/msx2+_schermen_in_basic.md @@ -0,0 +1,169 @@ + 2+ SCHERMEN IN BASIC. + + + ���� + ���� + ���� + ���� + + + Rond 1988 dacht men bij ASCII, jongens we zijn 't zat, d'r + moeten meer kleuren in die MSX2. Men is eens goed gaan + nadenken, en dat ging die sukkels daar bij ASCII niet erg + goed af. Want wat hebben die eikels toen besloten: Wel meer + kleurtjes, maar niet meer VRAM, en ja, dan krijg je gezeik. + Als de heren bij ASCII de volgende MSX serie (2+) nou gewoon + 512KVram hadden gegeven was er niets aan de hand geweest, + maar dat wou niet volgens ASCII. Maar goed, bij ASCII zijn + ze toen gaan nadenken hoe ze zo veel mogelijk kleuren in zo + weinig mogelijk VRAM konden krijgen en dat werd dus het YJK- + systeem. Toen ze alles af hadden hadden de heren bij ASCII + zelf ook wel door dat 't niets was en hebben toen ook maar + besloten het geplande MSX3 systeem -met Z800!- en dus de + nieuwe V9958 te laten voor wat het was en hebben toen maar + eerst even de 2+ uit gebracht die nog wel een Z80 had maar + dus wel de nieuwe V9958. Verder dan die V9958 is het nooit + gekomen, het V9978 idee werd in een vroeg stadium al + afgeblazen wegens te hoge kosten en te weinig potentiele + kopers. -ik had toen nog geen MSX- en de V9990 werd ook een + flop doordat het een poging was om meer computersoorten + tegelijk te bereiken. Op de MSX moeten wij het dus doen met + een zeer slome en in efficiente V9958. Dat er weinig mogelijk + is met de V9958 is wel duidelijk. Digi's worden perfect en + daar houdt 't wel zo'n beetje mee op. Toch valt 't allemaal + nog wel een beetje mee. Als je maar weet wat je doet. + + COLORSPILL + + Screen 2 is al net zo onbruikbaak als screen 12. Hetzelfde + verhaal geldt hier namelijk als bij Screen 12. Te veel + kleuren in te weinig geheugen. Toch zijn heel behoorlijke + resultaten te behalen op screen 2. Kijk maar naar de hele + Nemesis serie en klonen die Konami heeft uitgebracht. Als + jij een spel als Nemesis III speelt op je MSX2 werkt het toch + allemaal echt in screen 2. Ook al zijn de kleuren iets + aangepast. Ik ben er echt van overtuigd dat dit ook kan in + screen 12. Maar dan moeten er wel eerst fatsoenlijke + tekenprogramma's komen voor dit scherm. + + DE 'LOGICA' + + Om te begrijpen hoe de V9958 te werk gaat moeten we eerst even + kijken hoe alle data in 't Vram wordt gezet. + + Bit: | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | + -------------------------------------------------------- + Byte 1 | H | H | H | H | H | G | G | G | + Byte 2 | H | H | H | H | H | B | G | G | + Byte 3 | H | H | H | H | H | R | R | R | + Byte 4 | H | H | H | H | H | B | R | R | + -------------------------------------------------------- + + Hierbij staat de H voor helderheid, de R, de G en de B voor + respectievelijk R G en B. Een voorbeeldje. Iedereen klaagt + altijd over de kleur blauw die zo verdomd moeilijk op 't + scherm is te krijgen. Nou, als je weet wat je doet valt dat + wel mee. + + VPOKE &H0000,&B00000000 : VPOKE &H0001,&B00000100 + VPOKE &H0002,&B00000000 : VPOKE &H0003,&H00000100 + + De bits die voor blauw staan gewoon op 'aan' zetten en + klaar! Lastig is dus wel dat je altijd binnen een groepje + van 4 bytes moet blijven. En dat is dus 't hele probleem van + Screen 12. Verder is er niets aan de hand. De Helderheid kun + je gewoon vrij per pixel instellen zonder dat er allerlei enge + dingen gebeuren.. + Dat betekent dus dat er 32 helderheden per pixel kunnen + worden ingesteld en ik denk dat dat echt een sterk punt is + van Screen 12!! Als tekenprogramma's nou eens gewoon gebruik + maakten van de uit Screen5 bekende balkjes voor RGB en dan + nou eens gewoon die kleur in de 32 helderheden zou afbeelden + werd 't leven van de tekenaar op screen 12 al een heel stuk + makkelijker. Denk ik tenminste!! Goed, met deze gegevens + kunnen we al een heel eind verder, maar waarom werkt + Screen 10 dan wel goed in basic? Nou Screen10 bestaat gewoon + niet. Als dat alles niet een heel stuk duidelijker maakt + weet ik 't ook niet meer! Nee, Screen 10 bestaat aleen in + basic, de basic interpreter gaat met screen 10, dat + eigenlijk gewoon Screen 11 is, zodanig om dat alle + instructies dezelfde zijn als die uit Screen 8, zij het dat + de kleur en van 0 tot 15 lopen. Hoe werkt dit dan? + + Bit: | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | + ------+-----+-----+-----+-----+-----+-----+-----+-----+ + Byte 1| x | x | x | x | S | G | G | G | + Byte 2| x | x | x | x | S | B | G | G | + Byte 3| x | x | x | x | S | R | R | R | + Byte 4| x | x | x | x | S | B | R | R | + ------+-----+-----+-----+-----+-----+-----+-----+-----+ + + De x is hier variabel. Dit komt door de S in het geheel. + Die S is namelijk een Switch. Staat deze 'uit' dan geldt de + normale verwerking van de bits en zijn alle x bits de + helderheid.. Staat zo'n bit echter 'aan' dan schakelt + 'screen5' in en worden de xbits de 4bits kleurcodes die we + van screen5 kennen. De basis kleur van de vier pixels blijft + hetzelfde zodat zowel dat 16 paletkleur en als de 65536 + Screen10 kleuren kunnen worden afgebeeld in de Screen10 mode. + Omdat dus een bit wordt gebruikt voor de Switch gaat dus wel + de helft van de helderheden verloren aangezien er nog maar + 16 helderheden kunnen worden gemaakt. Een plaatje van + Screen12 naar 11 converteren is dus geen probleem aangezien + je alleen bit3 maar 'uit' hoeft te zetten. Dit kan gewoon + met een Box in 'kleur' &B 11110111 waar vervolgens een AND + op los moet worden gelaten waardoor bit3 altijd nul wordt + en de andere bitjes onaangetast blijven. + Op de disk staat een basiclisting die 256*212=54272 kleuren + op 't scherm tovert. Meer was op zich 't probleem niet zij + het dat er niet meer pixels beschikbaar zijn in screen 12 en + ik de pest heb aan interlacing. Maar hoe ga ik dan te werk? + Simpel, je begint door met een simpel rekentruukje alle + mogelijke (4096) basis kleuren op het scherm te toveren en + die vervolgens per basiskleur naar 32 pixel te copien. Je + hebt namelijk van elke basiskleur 32 pixels nodig om daar + later je H bits op aan te passen om de 32 helderheden te + krijgen. Als dan het hele scherm vol staat met van alle + basiskleuren 32 pixels kun je je helderheden er overheen + XORen zonder dat je de basis kleurbits aantast. Hiervoor + gebruik ik een truuk die eigenlijk niet mag maar goed, + niemand heeft het door. Dat kleuren aantal is natuurlijk + theoretisch want 't komt ongetwijfeld wel op een kleiner + aantal uit. + + &B11111101,&B11111000,&B11111000,&B11111000 + + is natuurlijk 't zelfde als + + &B11111011,&B11111000,&B11111000,&B11111000 + + Maar dat zal een ieder duidelijk zijn, als je twee 'groen' + bitjes aan zet maakt 't natuurlijk niet uit welke twee dat + zijn..ook al denkt mijn programma daar anders over. Waarom + ASCII ook zegt dat er maar 19000 nogwat kleuren zijn is mij + ook een raadsel. Van screen 5 zei men toch ook dat er een + palet uit 512 verschillende kleuren mogelijk was? R3 G3 B3 is + bij mij 't zelfde als B3 G3 R3 of niet soms? Nou weet ik ook + wel dat 't verschil tussen helderheid 31 en 30 niet te zien + is en dat als twee bits 'groen' aan staan het niet uit maakt + welke dat zijn maar laten we gewoon zeggen dat screen12 + 2 tot de 12e * 32 = 131072 kleuren heeft zodat we tegen al + dat Super Nintendo geweld op kunnen met ons 2plus-je. Tegen + PCers zeggen we dan gewoon weer 131072 basiskleuren in + 16 helderheden zodat hun 1,6 miljoen ook weer met bijna + 500000 is over schreden en dan kunnen we er weer tegenaan met + ons MSXje. Ik hoop dat ik met deze korte uitleg 't een en + ander duidelijk heb gemaakt en HOO WACHT!!! voor dat ik + het vergeet, of dat programmaatje van mij werkt weet ik eigen- + lijk niet... Ik heb namelijk een monochrome monitor hangen aan + m'n MSX-Turbo-R (wat ben ik ook een stakker.) zodat alle kleur + en zo'n beetje 't zelfde lijken en of ze dus ook echt verschil + lend zijn weet ik niet. Niet boos worden als 't niet zo is oke + boyz!? Oh ja, ik was aan het afsluiten dus daar ga ik dan maar + weer mee verder. Ik hoopte geloof ik dat ik jullie weer 't een + en ander heb duidelijk gemaakt en dat was 't dan wel voor deze + keer want 3 basic cursussen op een nummer is wel echt genoeg.. + + Tot de volgende keer dan maar!! + + Tobias "God, i'm perfect!" Keizer diff --git a/future_disk/19/pascal_8.md b/future_disk/19/pascal_8.md new file mode 100644 index 0000000..d7e874c --- /dev/null +++ b/future_disk/19/pascal_8.md @@ -0,0 +1,382 @@ + PASCAL (8) + + + ���� Hallie hallo, hier is Smael weer met zijn PASCAL cursus. + ���� Deel 8 deze keer (nog twee en dan is het alweer + ���� voorbij). In deel 8 gaan we dieper in op pointers. + ���� Vorige keer heb ik uitgelegd wat pointers zijn en wat je + ermee kunt. Nu is het dus tijd voor een groot voorbeeld. + Als voorbeeld neem ik een programma om namen en adressen op te + slaan (een soort database dus). Goed, daar gaat 'ie (wat + hebben we weer een plezier)!!(NvdR: ja nou) + + Het programma staat op de disk als 'PASCAL8.PAS'. De listing + vind je terug in deze tekst, maar alleen ter verduidelijking. + + De declaraties veronderstel ik bekend (moet je kunnen) en daar + ga ik dus niet verder op in. Wel staan ze hier even vermeld, + zodat je de rest van het programma begrijpt: + + PROGRAM Pascal8(Input,Output,Namen); + + CONST + Max = 30; + + TYPE + Wijs = ^Rij; + Rij = RECORD + Naam : String[Max]; + Adres : String[Max]; + Next : Wijs; + END; + + VAR + Namen : Text; + Keuze : integer; + Hoofd : Wijs; + Hulp : Wijs; + Aantal : integer; + + Ik ga dus verder met de eerste procedure, aangezien hier + misschien dingen zijn die je niet begrijpt. Als ik zo naar + deze procedure kijk, dan kom ik tot de ontdekking dat je + alleen het commando 'ClrScr' niet kent, maar dat de naam alles + duidelijk maakt. Let ook op hoe ik het probleem van de + toetsdruk oplos. De computer wacht totdat ik op de + toets heb geramd, daarvoor kun je dus alle letters inrammen + die je wil (ze zullen zelfs zichtbaar zijn op het scherm). + Niet erg netjes dus, maar dat kun JIJ verbeteren (gebruik de + functie 'KeyPressed'). Verder gesneden koek: + + PROCEDURE welkom; + + BEGIN (* welkom *) + clrscr; + writeln('Dit is een voorbeeldprogramma bij FD #19'); + writeln; + writeln('Dit programma maakt het mogelijk een'); + writeln('adressenbestand op te bouwen.'); + writeln('Het is een voorbeeld dat gebruik maakt'); + writeln('van pointers.'); + writeln; + writeln; + writeln('Enjoy !!'); + writeln; + writeln; + writeln; + write('Druk om verder te gaan.'); + readln; + END; (* welkom *) + + Ook deze procedure moet gesneden koek zijn (alleen maar wat + Writeln's en Readln's). Wederom kun je een en ander + verbeteren. Als je namelijk een verkeerde keuze maakt, dan + wordt op de volgende regel opnieuw naar je keuze gevraagd. + Maak je ongeveer 20 keer de verkeerde keuze, dan is het + keuzemenu niet meer te zien (uit het beeld geschoven) en dat + is niet zo netjes. Read it and weep : + + PROCEDURE menu(VAR keuze:integer); + + BEGIN (* menu *) + clrscr; + writeln('Je kunt kiezen uit :'); + writeln; + writeln('(1) Bestand inladen'); + writeln('(2) Persoon invoeren'); + writeln('(3) Overzicht personen'); + writeln('(4) Persoon verwijderen'); + writeln('(5) Bestand opslaan'); + writeln('(6) Stoppen'); + writeln; + writeln; + writeln; + keuze:=0; + REPEAT + write('Uw keuze : '); + readln(keuze); + UNTIL (keuze>=1) AND (keuze<=6); + END; (* menu *) + + Hier wordt het interessant. Er wordt een file ingelezen van + namen die ooit al eens zijn ingevoerd. Deze heb ik lekker + gemakkelijk gehouden. Vergelijk hem maar eens met de SAVE + procedure en je komt tot de ontdekking dat de namen omgekeerd + ingelezen worden. Wat bedoel ik? Als de namen in alfabetische + volgorde zijn weggeschreven (als voorbeeld), dan worden ze + anti-alfabetisch (dus net omgekeerd van Z naar A) ingelezen. + Let ook op de VAR (in de procedure-kop) bij Hoofd en Namen. + Bij Namen is het altijd verplicht (een file kan niet in het + geheugen gekopieerd worden), maar bij Hoofd zou ik het weg + kunnen laten. Of niet (een pointer kan in het geheugen + gekopieerd worden)? In dit geval niet!! + + Als er al ��n naam (of meerdere) ingevoerd waren, dan kon ik + het weglaten (moet de rest wel achteraan toegevoegd worden) + aangezien Hoofd dan niet meer hoeft te veranderen (let vooral + op de voorgaande opmerking). Nu wordt elke nieuwe naam vooraan + in de lijst bijgeschoven en dus veranderd Hoofd bij elke naam. + Conclusie : VAR kan niet weggelaten worden (anders ben je je + namen kwijt als je terugkeert naar het hoofdprogramma). + + Let ook op het gebruik van de EOF functie. Ik hou er rekening + mee dat een file verminkt is. Ik zou kunnen volstaan met de + EOF controle bij de WHILE-lus, maar als de file verminkt is, + dan gaat het fout bij het inlezen van het adres. Gevolg is een + crash van de computer en dus zijn al je gegevens weg. Let + hier op bij het programmeren van een grote toepassing. Let + tevens op de 'Close(Namen)' aan het einde van de procedure, + deze is geplaatst om problemen te voorkomen indien je na het + inlezen het programma be�indigd (er staat immers nog een file + open). Verder bekend (neem ik aan) : + + PROCEDURE Laden(VAR Hoofd:Wijs;VAR Namen:Text); + + VAR + Hulp : Wijs; + + BEGIN (* Laden *) + Assign(Namen,'adres.txt'); + Reset(Namen); + WHILE NOT EOF(Namen) DO + BEGIN + New(Hulp); + IF NOT EOF(Namen) THEN + Readln(Namen,Hulp^.Naam) + ELSE + Hulp^.Naam:=''; + IF NOT EOF(Namen) THEN + Readln(Namen,Hulp^.Adres) + ELSE + Hulp^.Adres:=''; + Hulp^.Next:=Hoofd; + Hoofd:=Hulp; + END; + Close(Namen); + END; (* Laden *) + + Ook deze procedure moet geen echte problemen opleveren (zeker + niet als je de vorige procedure begrepen hebt). Hier worden + namen toegevoegd aan de lijst (wederom vooraan). Ik houd er + rekening mee dat de gebruiker gekke dingen doet, vandaar de + dubbele controle op het invoeren van een lege regel. Let ook + op de twee Dispose opdrachten op het einde van de procedure!! + Again, read it and weep : + + PROCEDURE Plus(VAR Hoofd:Wijs); + + VAR + Hulp : Wijs; + + BEGIN (* Plus *) + New(Hulp); + ClrScr; + Writeln('Toevoegen van naam aan lijst'); + Writeln; + Writeln; + Writeln('Geef naam en adres (RETURN is stoppen).'); + Writeln; + Write('Geef naam : '); + Readln(Hulp^.Naam); + IF Hulp^.Naam<>'' THEN + BEGIN + Write('Geef adres : '); + Readln(Hulp^.Adres); + IF Hulp^.Adres<>'' THEN + BEGIN + Hulp^.Next:=Hoofd; + Hoofd:=Hulp; + END + ELSE + Dispose(hulp); + END + ELSE + Dispose(Hulp); + END; (* Plus *) + + Aan deze procedure maak ik geen woorden vuil (buiten het feit + dat ik je wijs op het handige gebruik van de MOD functie bij + de REPEAT-UNTIL): + + PROCEDURE Print(Hoofd:Wijs); + + VAR + Teller : integer; + Hulp : Wijs; + + BEGIN + Hulp:=Hoofd; + Teller:=0; + REPEAT + ClrScr; + REPEAT + IF Hulp<>NIL THEN + BEGIN + Writeln(Hulp^.Naam); + Writeln(Hulp^.Adres); + Hulp:=Hulp^.Next; + END + ELSE + BEGIN + Writeln; + Writeln; + END; + Writeln; + Teller:=Teller+1; + UNTIL (Teller MOD 7)=0; + Write('Druk om verder te gaan.'); + Readln; + UNTIL Hulp=NIL; + END; (* Print *) + + Dit is natuurlijk de meest interessante procedure. Je zou hem + nu echter (na het lezen van Laden en Plus) zo goed als moeten + kunnen dromen. Nee, dat is maar een grapje(NvdR: haha). + Zelfs ik heb moeten denken hoe je dit gemakkelijk en snel + zou kunnen oplossen. Door een truukje gebruik ik maar twee + hulppointers in plaats van drie (ik gebruik de Next van + Hulp1 omdat die toch niet wordt gebruikt). Wat bij dit + soort procedures lastig is zijn niet de normale gevallen + (een naam middenin de lijst verwijderen), maar de bijzondere + gevallen (een naam in het begin of een naam op het einde + verwijderen). Probeer dit ook altijd goed uit als je zoiets + maakt, zodat je niet voor verassingen komt te staan. + Enjoy: + + PROCEDURE Min(VAR Hoofd:Wijs); + + VAR + Hulp1 : Wijs; + Hulp2 : Wijs; + + BEGIN (* Min *) + New(Hulp1); + ClrScr; + Writeln('Verwijderen van naam uit de lijst'); + Writeln; + Writeln; + Writeln('Geef naam (RETURN is stoppen)'); + Writeln; + Write('Geef naam : '); + Readln(Hulp1^.Naam); + IF Hulp1^.Naam<>'' THEN + BEGIN + Hulp2:=Hoofd; + IF Hoofd^.Naam=Hulp1^.Naam THEN + BEGIN + Hoofd:=Hoofd^.Next; + Dispose(Hulp2); + END + ELSE + BEGIN + WHILE Hulp2<>NIL DO + IF Hulp2^.Naam<>Hulp1^.Naam THEN + BEGIN + Hulp1^.Next:=Hulp2; + Hulp2:=Hulp2^.Next; + END + ELSE + BEGIN + Hulp1^.Next^.Next:=Hulp2^.Next; + Dispose(Hulp2); + Hulp2:=NIL; + END; + END; + END; + Dispose(Hulp1); + END; (* Min *) + + Tja, moet ik dit nog bespreken? Dacht het niet : + + PROCEDURE Saven(Hoofd:Wijs;VAR Namen:Text); + + VAR + Hulp : Wijs; + + BEGIN (* Saven *) + Assign(Namen,'adres.txt'); + Hulp:=Hoofd; + Rewrite(Namen); + WHILE Hulp<>NIL DO + BEGIN + Writeln(Namen,Hulp^.Naam); + Writeln(Namen,Hulp^.Adres); + Hulp:=Hulp^.Next; + END; + Close(Namen); + END; (* Saven *) + + Hier wordt natuurlijk alles samengevoegd, maar dat het je al + begrepen: + + BEGIN (* HOOFDPROGRAMMA *) + New(Hoofd); + Hoofd:=NIL; + welkom; + REPEAT + menu(keuze); + CASE Keuze OF + 1 : Laden(Hoofd,Namen); + 2 : Plus(Hoofd); + 3 : Print(Hoofd); + 4 : Min(Hoofd); + 5 : Saven(Hoofd,Namen); + END; + UNTIL keuze=6; + Hulp:=Hoofd; + WHILE Hoofd<>NIL DO + BEGIN + Hoofd:=Hoofd^.Next; + Dispose(Hulp); + Hulp:=Hoofd; + END; + END. (* HOOFDPROGRAMMA *) + + Dat was het. Weinig commentaar van mij dit keer, maar dat komt + omdat je dit zelf moet uitzoeken. Het programma werkt (ik heb + het uitvoerig getest) en dus kun je hier kijken hoe het moet. + Wat je moet doen om zelf meer te leren is het programma + aanpassen (daar heb ik het voor gemaakt). Dit programma bevat + alleen maar de namen en adressen (dat adres is niet compleet) + en moet dus eigenlijk uitgebreid worden met postcode, + woonplaats en telefoonnummer. Vandaar de volgende opdrachten: + + (1) Verbeter de invoerroutines, zodat een en ander mooier + uitziet als er een fout wordt gemaakt. + (2) Breid het programma uit, zodat ook de postcode, + woonplaats en het telefoonnummer van de betrokkene + ingevoerd en bewaard kan worden. + (3) Sorteer de gegevens alfabetisch (Tip : maak gebruik van + een bubblesort algoritme, dat is het gemakkelijkst bij + pointers). + + Smael, wat is bubblesort? Bubblesort is een sorteerroutine. + Hoe werkt dat? Als volgt : + (1) X <- 1 + (2) Vergelijk element X en X+1 met elkaar + (3) ALS element X+1 < element X DAN + wissel element X en element X+1 + (4) X <- X+1 + (5) ALS nog elementen DAN + ga naar stap 2 + (6) ALS gewisseld (tijdens ��n doorgang) DAN + ga naar stap 1 + En gesorteerd is die hap. + + Bubblesort werkt dus met doorgangen. Per doorgang zorg je + ervoor dat minimaal 1 element op de goede plaats komt (je + schuift dat element telkens voor je uit). Na ��n doorgang heb + je dus alle elementen minimaal ��n maal bekeken. Zolang je dus + wisselt (al is het maar ��n keer per doorgang) ben je nog niet + klaar met sorteren. Dit lijkt niet effici�nt, maar is het wel + (bubblesort is ongeveer 5 keer sneller dan de ouderwetse + sorteermethode met de twee FOR-NEXT loops) en daarbij is het + ook nog eens het gemakkelijkst bij pointers (hoe wil je dat + met twee FOR-NEXT loops oplossen?). + + Zo, dat was het. Tot de volgende keer, dan gaan we het hebben + over recursie (en dat is pas ECHT leuk). Groetjes, + + Jeroen 'FD^.Next^.Nummer:=20' Smael + + C YA @!! diff --git a/future_disk/20/data_compressie_4.md b/future_disk/20/data_compressie_4.md new file mode 100644 index 0000000..462aacc --- /dev/null +++ b/future_disk/20/data_compressie_4.md @@ -0,0 +1,29 @@ +--- Data Compressie 4 --- + + ���� + ���� + ���� + ���� + + + + Hoi, nadat ik vorige keer in verband met Tilburg geen kans + gezien had om nog een aflevering te maken zal ik dat proberen + nu goed te maken. Vorige keer beloofde ik dat we de methode + die ik daar beschreef in code zouden gaan omzetten. + + Nou, dat is gebeurd, maar omdat ik maar weinig tijd + heb(NvdR: smoesjes, eikel), is enkel de listing op deze disk + geplaatst, van een compleet werkende in en uitpakker onder + DOS. + + De listing staat onder de naam "RUNLEN.GEN" op de schijf. + Die is te assembleren met GEN80. In Wbass2 inladen kan ook, + maar dan zul je eerst alle tab's moeten laten vervangen door + spaties (inconsequentie van Wbass2). + + Veel plezier ermee en volgende keer volgt de uitleg bij de + listing. + + + Jan-Willem van Helden diff --git a/future_disk/20/moonblaster_music_cursus_3.md b/future_disk/20/moonblaster_music_cursus_3.md new file mode 100644 index 0000000..e700d14 --- /dev/null +++ b/future_disk/20/moonblaster_music_cursus_3.md @@ -0,0 +1,158 @@ + MOONBLASTER CURSUS(3) + + + Jaahhh, daar is 'ie alweer. Het derde deel van de bij + jullie zoooo favoriete MoonBlaster cursus. De enige + sectoren op de FutureDisk die helemaal kapot gelezen + worden, de enige tekst die je printer laat doorbranden, + de enige die....(NvdR: de enige tekst die je nekvel + rechtop laat staan als je al die taalfouten eruit moet + halen!) + + Ahum, ik ben weer eens goed op dreef, ik heb hier totaal + geen zin in, mijn inspiratie is verdwenen (heb ik die + eigenlijk ooit wel gehad?) en aan deze cursus heeft alleen + Sunrise iets, omdat dit in hun ogen de enige cursus op de FD + is die het verdient om afgekraakt te worden. Maar goed, om + effe back to the point te komen, de vorige keer had ik + nogmaals de accoorden besproken. Ik zou hier nog een tekst + over ontvangen van dhr. Boer, aangezien ik alles de + vorige keer uit m'n hoofd moest doen (goed h�?). Deze tekst + heb ik nog steeds niet ontvangen, en ik ga er vanuit dat die + ook niet meer komt(NvdR: wat kinderachtig). Verder was er + niemand van betekenis met commentaar, dus ga ik gewoon verder + met het volgende onderdeel. Omdat ik nu ook eindelijk in + het bezit ben van een OPL-4 zal ik ook regelmatig verwijzen + naar dit Japanse muziekwondertje. Als je mazzel hebt kun je + zelfs de drumvoorbeelden uit deze cursus nog voor OPL-4 op + deze disk vinden...(ALLE MUZIEK VOOR OPL-4 STAAT INGEPAKT OP + DE DISK ONDER DE NAAM OPL4.PMA ... UITPAKKEN DUS DIE HANDEL + MET PMEXT.COM) + + MY FIRST SONY DRUMCOMPUTER + + Een zeer belangrijk deel in een MSX-muziekstuk wordt + ingenomen door de drums. Bij erg rustige nummers kun je het + soms ook nog achterwege laten, maar vaak zijn de drums toch + een vereiste. Als je nog maar net begonnen bent met je te + verdiepen in MoonBlaster, dan is het misschien verstandig om + een nummer altijd te beginnen met de drums, aangezien dit je + heel gemakkelijk helpt om ritme te houden. Voor de bezitters + van een MuziekModule allereerst nog een kleine tip: als je + meerdere drumkits gebruikt is het verstandig om voor ieder + drumgeluid toch hetzelfde drumnummer te gebruiken. + Bijvoorbeeld dat nummer 1 steeds een bassdrum is. Dit werkt + in de praktijk een stuk gemakkelijker. + Nog een tip voor OPL-4: als je zoveel sample-kanalen hebt, + ga je natuurlijk niet meer met de drums zitten klooien. Het + is echt van harte aan te bevelen dat je voor de drums + meerdere kanalen gebruikt. Met drie drum-kanalen kun je al + hele mooie dingen doen! + + EN NU? + + En dan nu de eigenlijke uitleg. Je hebt in MoonBlaster 2 + mogelijkheden wat betreft de maat van het muziekstuk. Dit + zijn namelijk een vierkwartsmaat (4/4); dit is gewoon ��n + hele pattern. Ook een driekwartsmaat (3/4) is mogelijk, dit + doe je door op elke pattern op de 12 (kan ook 11 zijn, ik + heb het niet gecontroleerd) stap een ENdOfPage (ENDOP) te + zetten. Ik ga nu uit van een vierkwartsmaat, aangezien die + het meeste gebruikt wordt. Als je dit eenmaal onder, boven + of tussen de knie hebt, dan lukt de 3/4-maat waarschijnlijk + ook wel (zie ook MDDRUM04.MBM). Op deze FD is trouwens ook + een muziekje in 3/4 maat geschreven, laad FUTURE01.MBM maar + eens in... Voor een heel erg standaardritme (zie ook + MBDRUM01.MBM op de disk) kun je het beste bovenaan de + pattern beginnen met een bassdrum. Op de FM-Pac voer je dit + in door op het drumkanaal te gaan staan en op "1" te drukken. + Met de MuziekModule hangt het er vanaf waar je de bassdrum + hebt staan, maar meestal zal dit ook de "1" zijn. Vervolgens + sla je ��n stap over en zet je op de plaats waar je nu staat + een hihat neer. Daarna sla je alweer een plaats over en zet + je een snaredrum neer, waarna je weer een plaats overslaat en + een hihat plaatst. Let er bij de OPL-4 wel op dat je + GM-Percussion geselecteerd hebt. Je krijgt dus het volgende + idee (dit is van links naar rechts omdat 't anders zoveel + ruimte inneemt): + + STEP: 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 + DRUM: 1 - 3 - 2 - 3 - 1 - 3 - 2 - 3 - + + (voor OPL-4:) + + STEP: 01 02 03 04 05 06 07 08 + DRUM: C 4 F#4 D 4 F#4 + + (Hier staat slechts de helft, om het overzichtelijk te + houden. Dit kun je natuurlijk eindeloos blijven herhalen). + + Nu klinkt het meestal mooier als je hier wat variaties in + aanbrengt, zoals je kunt zien in de file MBDRUM02.MBM en + MBDRUM03.MBM. Let er echter wel steeds op dat je maar beter + (in 't begin) drie (lege) posities tussen de bassdrum en de + snaredrum houdt. Later kun je dit altijd wel veranderen, en + je zult zien dat dit opvallende resultaten kan opleveren. + Mocht je overigens niet weten wat een bassdrum of een snare- + drum is, kijk dan naar het onderstaande lijstje: + + DRUM: MSX-Music (FM-Pac) MSX-Audio (MuziekModule) + + Bassdrum Drumnummer 1 Drumnummer 1 + Snaredrum Drumnummer 2 Drumnummer 2 + Hihat (closed) Drumnummer 3 Drumnummer 3 + Cymbal Drumnummer 4 Drumnummer 4 + Tom Drumnummer 5 Drumnummer 5 + Hihat (open) ------------ Drumnummer 6 + + OPL-4 bezitters kunnen dit lijstje wel vergeten, aangezien + alle drums al op de achterzijde van de handleiding staan. + + Bij het bovenstaande lijstje ga ik van een aantal dingen + uit: + + - Voor de MuziekModule heb je de drumkit FUTURKIT.MBK + ingeladen, waarna je ze kunt beluisteren in 't samplemenu + (F3). + - Voor FM-Pac ga ik uit van de drums die je hebt als je MB + opstart. Je kunt nu de drums beluisteren door in het + FM-drummenu (F8) te kiezen voor "Edit drumfrequency", + waarna je de drums kunt afspelen met F1 t/m F5. + + Let er wel op dat Fm-drums meestal mooier klinken als je + meerdere geluiden tegelijk gebruikt. Ook kunnen de PSG drums + een uitkomst bieden... + Voor de volledigheid heb ik ook nog een ritme gemaakt in de + 3/4 maat (zie MBDRUM04.MBM). + + MUSICAL CREATURES + + Het is mijn bedoeling om voor deze cursus ��n of twee + nummers op te bouwen met behulp van deze cursus. Zo kun je + op deze disk al twee voorbeelden beluisteren waar de drums + en de accoorden al gebruikt worden.... Misschien... want + echt veel tijd heb ik niet meer. Kijk maar op de disk! + Overigens, er staan voor de gelukkige bezitters van een + OPL-4 ook nog een aantal songs op.... Voor de volgende keer + probeer ik mijn leven te beteren en jullie plat te gooien + met muziek(achtige) zooi. Ook zal ik meer aandacht aan de + OPL-4 besteden, maar dat merk je dan wel... + + I QUIT WITH THIS BULLSHIT + + Ja mensen, jullie hebben het goed gelezen. Ik kap er voor + deze keer maar mee, 'k heb er geen zin meer in. Je kunt + zoals gewoonlijk op- of aanmerkingen sturen naar het + redactieadres, of desnoods (tweede keuze) doorgeven aan + mij. + +Sayonara! + + Jorrith "I don't like this" Schaap + + + Jorrith Schaap + Erasmusweg 7 + 9602 AB Hoogezand + Nederland + diff --git a/future_disk/20/muizen_in_basic.md b/future_disk/20/muizen_in_basic.md new file mode 100644 index 0000000..e8ab26e --- /dev/null +++ b/future_disk/20/muizen_in_basic.md @@ -0,0 +1,101 @@ + + MUIZEN IN BASIC + + ���� + ���� + ���� + ���� + + Wederom een tekstje voor de wat minder gevorderden. Dus al + die oude rotten die eigenlijk alles al weten van Basic + moeten maar gewoon ML gaan leren of zo... De muis... men + plugt 'm in poort 1 of 2, men rammelt een beetje met ons + electronische knaag diertje en zie daar, de muiscursor + huppelt vrolijk 't scherm door. Om deze schokkende gebeur- + tenis te achterhalen gebeurt er nog al 't een en ander in + ons MSXje. De technische uitleg wou ik dan maar achterwege + laten maar het hoe en wat betreffende 't uitlezen in basic + wou ik wel even behandelen... + +PAD + Dat is 't commando waar 't allemaal mee dient te gebeuren... + Pad wordt voornamelijk gebruikt om de status van de muis en + de trackball uit te lezen. PHILIPS heeft echter destijds + ooit ook nog eens van die shit zoals tekentableuas en + lichtpennen uitgebracht die ook met pad werken. + + In de praktijk zal het uitlezen ook nog wel mee vallen, maar + het checken of er wel een muis is aangesloten valt over 't + algemeen tegen. Dat valt namelijk niet te checken op een MSX. + Er is echter wel een truukje dat kan worden gebruikt, maar dat + is niet echt netjes(NvdR: net of dat iemand boeit?!). + + De syntaxis + + A=PAD(X) + De waarde van PAD komt hierdoor in A terecht waarbij in X + de specifieke gegevens voor PAD dienen te worden opgegeven. + 12 of 16 Zal altijd -1 geven maar MOET worden opgevraagd + voordat X en Y worden bepaald. + 13 of 17 De verandering op de X-as. + 14 of 18 De verandering op de Y-as. + + Het linker getal is steeds voor poort 1, het rechter voor de + tweede poort. De beste manier om dan de muis coordinaten bij + te houden is gewoon steeds PAD(13) by het X-coordinaat op te + tellen en PAD(14) bij het Y-coordinaat op te tellen. + PAD(12) heeft dus geen functie maar moet wel voor 't + opvragen van PAD(13) en PAD(14) worden bepaald. + Een voorbeeld: + + 10 SCREEN5:X=127:Y=105 + 20 DUMMY=PAD(12):X=X+PAD(13):Y=Y+PAD(14) + 30 IFX<0THENX=0:ELSEIFX>255THENX=255 + 40 IFY<0THENY=0:ELSEIFY>211THENY=211 + 50 PSET(X,Y),15:GOTO20 + + Door het bewegen van de muis kunnen we nu keurig een lijntje + trekken over 't scherm. Maar als we nou ook af en toe geen + lijnje willen trekken? Goed, gaan we weer: + + 10 SCREEN5:X=127:Y=105 + 20 DUMMY=PAD(12):X=X+PAD(13):Y=Y+PAD(14) + 30 IFX<0THENX=0:ELSEIFX>255THENX=255 + 40 IFY<0THENY=0:ELSEIFY>211THENY=211 + 50 IFSTRIG(1)THENPSET(X,Y),15:GOTO20:ELSEGOTO20 + + Nu kunnen we de muis vrijelijk door 't scherm laten bewegen + zonder dat we een lijntje trekken. Pas als we trig1 inhouden + zal er een lijntje worden getrokken. Maar nu weten we dus + niet waar de muiscursor is als we niet aan 't tekenen zijn. + Hiervoor voegen we weer twee regels toe: + + 15 SPRITE$(1)=CHR$(&H80) + 45 PUTSPRITE 0,(X,Y),14,1 + + Nu zal er op de plek van de muis-coordinaten ook echt een + muiscursor verschijnen; nou ja, een grijs stipje. + Maar Tobias zou Tobias niet zijn als ie niet nog een + netelig probleem kon bedenken. Juist ja, misschien zit de + muis wel in poort 2. + + 05 X=0:FORL=0TO25:DUMMY=PAD(12):X=X+PAD(13):NEXTL:IFX>-5 + ANDX<5THENMO=12:TR=1 + 10 X=0:FORL=0TO25:DUMMY=PAD(16):X=X+PAD(17):NEXTL:IFX>-5 + ANDX<5THENMO=16:TR=3 + 15 SCREEN5:X=127:Y=105:SPRITE$(1)=CHR$(&H80) + 20 D=PAD(MO):X=X+PAD(MO+1):Y=Y+PAD(MO+2) + 30 IFX<0THENX=0:ELSEIFX>255THENX=255 + 40 IFY<0THENY=0:ELSEIFY>211THENY=211 + 50 PUTSPRITE0,(X,Y),14,1 + 60 IFSTIRG(TR)THENPSET(X,Y),15:GOTO20:ELSEGOTO20 + + Nu hebben we eindelijk een routine die met de muis in elke + poort een muis cursor op 't scherm zet en bij een knop op + de linker vuurknop een punt zet. + + Wauw! fantastisch, heb ik weer en half uur zitten typen en + weer geen hond die 't leest. A well, that FutureDisk life! + (NvdR: what life?) + +Keizer... diff --git a/future_disk/20/turbo-r_basic.md b/future_disk/20/turbo-r_basic.md new file mode 100644 index 0000000..a9fc0e5 --- /dev/null +++ b/future_disk/20/turbo-r_basic.md @@ -0,0 +1,177 @@ + THIS TEXT WAS NOT SPONSORED BY WEBBER... + + De turbo en basic, een prima combinatie. + Veel mensen hebben de heilzame invloed van de R800 in hun + Turbo-R wel gemerkt, vooral in basic, wat vroeger nog in ML + moest kan nou ook in basic, met de R800 aan, dat wel. + + Toch weten veel mensen niet hoe alles nu zo'n beetje wordt + aangestuurd, en dat is jammer. Want zelfs de dingen die in + eerste instantie niet zo nuttig lijken zijn toch leuk om aan + te sturen, en dat kan zelfs in basic.. Lees, en ontdek. + +DE LEDJES + + Op de Turbo zitten een aantal ledjes, 7 om precies te zijn. 't + is altijd leuk om hiermee van die Knight Rider effectjes uit + te halen, vandaar even de aansturing. De Caps en de Kana leds + zijn neem ik aan bekend. De power led en de FDD led kun je in + basic niets mee, hoewel je, als je heel moeilijk doet, in ML + de FDD led meen ik WEL aan kan zetten. Blijven er drie leds + over, de RENSHA led, de R800 led en de PAUSE led. De RENSHA + turbo schakeling valt helaas niets mee te doen op ons MSX-je. + Dit hele ding is hardwarematig waarbij er vrijwel geen + software-matige truukjes worden uitgehaald. Er kan met de + potmeter worden ingesteld hoe lang de blokpuls die + gegenereerd wordt moet zijn en vervolgens word deze geORd + met PSG register 14 bit 4 en de 0de bit van rij8 van de + Toetsenbord matrix. Zie hiervoor vorige FD. Dit gebeurt + dus eigenlijk allemaal hardware-matig en je hebt hier dus + niets aan. Zou je de lengte van een puls willen meten moet + er nog eerst op een trig A worden gedrukt. Blijven de TURBO + en PAUSE led over: + + TURBO led: OUT &HA7,&B00000001 + PAUSE led: OUT &HA7,&B00000001 + + Waarbij de 1 natuurlijk aan is op de juiste plaats. Alle + combinaties met bit 0 en 7 zijn natuurlijk mogelijk. Op de + disk staat nog wel even en replayertje dat even leuk laat + zien hoe de ledjes bijvoorbeeld kunnen worden gebruikt. + +DE FIRM-SOFTWARE-SWITCH. + + In beide turbo's zit een aanzienlijke hoeveelhed zogenaamde + FIRM-SOFTWARE. VIEW op de GT en HIRO op de ST. Deze software + staat op ROM en is dmv de schakelaar op de kast aan en uit te + schakelen. Het leuke is dat de stand van deze schakelaar in + basic is uit te lezen. Dit is op zich wel grappig om ook + eens in eigen programmatjes te gebruiken zoals je ook in + mijn replayertje kan zien. In $E4 wordt een 5 gezet om de + swith uit te lezen waarna de INP waarde nog even met 64 + geANDd moet worden om 't uiteindelijke resultaat te + krijgen. + + 10 OUT &HE4,5 : SW=INP (&HE5) AND 64 + 20 IF A=64 THEN PRINT "ON" ELSE PRINT "OFF" + +CANCEL & CONFIRM TOETSEN + + De Turbo's hebben ook nog een drietal extra toetsen. De, om ze + maar een naam de geven, Cancel en Confirm toetsen en dus de + Pauze toets. De pauze toets zat al eerder op 2+n maar toen was + het nog een hardware matige schakelaar. Bij de Turbo is de + pauze toets echter software matig en is naar mijn mening nu + pas een echte toets. Met de pauze toets kun je echter niets in + basic omdat onder basic de interrupt normaal gesproken altijd + aan is en dan dus de computer ook echt gaat pauzeren. In MC is + het echter wel degelijk mogelijk om met alle Turbo-toetsen te + spelen. Dan blijven dus de CANCEL en CONFIRM toetsen, naast de + spatiebalk, over. Deze zitten gewoon in de toetsenbord buffer + en wel op resp bit 3 en bit 1 van rij 11. Zie over details van + toetsenbord uitlezing de vorige FD. Om deze toetsen uit te + lezen brijg je dus het volgende programmaatje. + + OOPS, toen bleek dit inderdaad rij 11 te zijn, en of die ook + echt op adres '11' staat weet ik niet, nou goed, een gokje dan + maar hoe 't zou kunnen werken in BASIC, of dit zo is weet + ik niet. + + 10 IF (PEEK(&HFBF0)AND&B00000001)=0 THEN PRINT "CONFIRM" + 20 IF (PEEK(&HFBF0)AND&B00000100)=0 THEN PRINT "CANCEL" + 30 CLS:GOTO10 + + Anders kan 't altijd nog in ML met: + + GETKEY: LD A,11 + CALL $0141 + BIT 1,A + JP Z,CONFIR + BIT 3,A + JP Z,CANCEL + JP GETKEY + +DE PCM-SAMPLER + + En dan als laatste nog de PCM waar ik niet al te veel tijd + aan wil besteden omdat die eigenlijk al gesneden koek is + voor de meesten. + De syntaxis: + + CALL PCMREC (@,,,[SV],[RL],[S]) + CALL PCMPLAY (@,,,[S]) + + SA: Start Adres, &H0000 - &HFFFF + EA: Eind Adres, &H0000 - &HFFFF + FR: Frequentie, 0 - 3 + + SV: Start Volume, reageert bij bepaald volume. + RL: Run Length, soort runlength, telt aantal 'nullen' + S: opslag in VRAM in plaats van RAM. + + Die runlength wil ik nog wel even op terug komen. Die is + namelijk niet wat je zou vermoeden. Als de computer + namelijk een bepaalde tijd 'stilte' registreert dan treedt, + indien aangezet, deze optie in werking. De tijd die de + stilte duurt wordt opgeslagen i.p.v de data die deze stilte + beschrijft. Nog even een voorbeeld programmaatje. + + 05 ' SAMPLE.BAS + 10 IF PEEK(&HF677)=&HC0 THEN GOTO 30 + 20 POKE &HF677,&HC0 : POKE &HC000,0 : RUN "SAMPLE.BAS" + 30 FORP=2TO15:OUT &HFE,P:_PCMREC (@&H8000,&HBFFF,0):NEXTP + 40 FORP=2TO15:OUT &HFE,P:_PCMPLAY(@&H8000,&HBFFF,0):NEXTP + 50 OUT &HFE,1 : POKE &HF677,&H80 : POKE &H8000,0 : NEW + + En zie daar, en bere lange sample. Nou dat was 't dan wel + voor deze keer want ik ben 't nu wel zat, see ya'll... + +Keizer + + Wat ben ik toch ook een lekker slim joch, heb ik 't over de + Turbo-R, vergeet ik 't belangrijkste, de R800. Deze is he- + laas niet in BASIC met een call of zo aan te zetten, dit moet + echt in machinetaal gebeuren. Door echter een zestal getallen + in het geheugen te poken wordt dit probleem opgelost... + + 10 FOR L=0 TO 5: READ V: POKE &HC000+L,V: NEXT L + 20 POKE &HC001,&B10000000 'Z 80 MODE + 30 POKE &HC001,&B10000001 'R800 MODE + 40 POKE &HC001,&B10000010 'DRAM MODE + 50 DEFUSR=&HC000:A=USR(0): DATA &H3E,&H00,&HCD,&H80,&H01,&HC9 + + Nou, als 't goed is werkt dit wel dus dan is deze text nu echt + aan z'n einde gekomen. Nog even melden dat de DRAM mode dus de + laatste 64kB van je geheugen afsnoept, maar deze is dan ook 'n + stuk sneller dan de R800 modus, als je veel BIOS routines gaat + gebruikem tenminste... Maar dat zal in BASIC vaak wel het + geval zijn.... + + Groeten, Keizer... + + En dit werkt natuurlijk niet nu ik er over na denk... + Die routine zit natuurlijk in de SUB-ROM en niet in de + Main Rom... + Een nieuwe routine dus.... + + 10 FOR L=0 TO 6:READ V:POKE &HC000+L,V:NEXT L:DEFUSR=&HC000 + 20 A=&B10000000 'Z 80 MODE + 30 A=&B10000001 'R800 MODE + 40 A=&B10000010 'DRAM MODE + 50 Z=USR(A): DATA &HDD,&H21,&H80,&H01,&HCD,&H5F,&H01,&HC9 + + Hierbij mag je de eerste 1 weglaten als je niet wilt dat de + led mee veranderd. Well, now it should work.... + + Keizer. + + En daar ben ik weer... -ik zal ook eens een tekst in een keer + typen- En weer eens met nieuws omdat ik nooit ene flikker uit + voer. Nou ja, bijna nooit. Door het poker spelletje van deze + keer heb ik weer eens geen tijd gehad om het beloofde + programmaatje te maken dus U kunt vrolijk vloeken en + schelden op het nummer 046-374322, het nummer van de + hoofdredacteur...(NvdR: die U vervolgens doorstuurt naar de + crimineel in kwestie Dhr. T.K.K. Keizer. 05202-31343) + + Tobias Keizer. diff --git a/future_disk/21/call_kanji.md b/future_disk/21/call_kanji.md new file mode 100644 index 0000000..2783328 --- /dev/null +++ b/future_disk/21/call_kanji.md @@ -0,0 +1,178 @@ + Een aardige uitleg door de DHR KEIZER. Hoe typ ik het Japanse woord voor "schaamhaar" in zonder dat ik het zelf weet? + + +CALL KANJI?? + + ���� + ���� + ���� + ���� + + Yep, voor de 2-plussers -neen, dit zijn geen kleuters of + peuters- onder jullie wel. Iedereen kent dat _Kanji gedoe + wel, veel mensen weten echter niet dat dit meer dan wat + grotere lettertjes op kan leveren. + + Modi: + De Kanji mode op de 2+ kent weer een aantal verschillende + modi. Vier om precies te zijn. Het verschil zit hem vooral + in de letter-breedte en letter hoogte. De verschillen: + _KANJI0 ; 8*16, low res, non interlace. + _KANJI1 ; 6*16, low res, non interlace. + _KANJI2 ; 8*16, highres, interlace. + _KANJI3 ; 6*16, highres, interlace. + + De 8*16 en de 6*16 staan voor de pixel breedte/hoogte van de + ASCII karakters. Het normale font wordt namelijk uitgezet. In + plaats hiervan wordt er een speciaal karaktersetje door de Jis + rom ingeschakelt dat de normale ascii letters moet vervangen. + De JIS-Karaktes -zoals de Kanji-letters heten- zijn echter + altijd 16*16. De jis letters uit mode 0 & 1 en uit mode 2 & 3 + zijn dus verder gelijk. Het voordeel van deze schermen was dus + eigenlijk alleen voor de Japanners merkbaar. Ze konden immers + kanji op hun scherm krijgen die leesbaar zijn. Voor ons zijn + er echter ook voordelen. Zo is nu eindelijk dat gepiemel met + OPEN "GRP:" AS #1 afgelopen in een grafisch scherm. Staat de + kanji-driver aan, dan volstaat een PRINT gewoon. Tevens kunnen + commando's als locate en input na het aanroepen van de kanji + driver gewoon gebruikt worden in de grafische schermen. Maar + zelf vind ik bijvoorbeeld de karakters in KMODE2 een stuk + mooier dan die iele ascii lettertjes. Jammer is wel dat de + interlacing na lange type sessies gaat storen. + + Niet alles werkt: + Neen helaas niet, maar daar hebben de heren bij ASCII wel een + oplossing op gevonden. Zo zal het commando CLS domweg een + "Illegal function call" opleveren. Evenals COLOR= niet meer + toegestaan is. De oplossing hiervoor is vrij simpel. _CLS doet + het prima in een kanji scherm, terwijl _PALETTE de oplossing + blijkt te zijn voor het COLOR= probleem. Verder vind ik het + toch wel storend dat het niet mogelijk is om de gewenste kanji + op de gewenste X-Y positie te krijgen in een grafisch scherm. + De enige manier waarop dit mogelijk is, is door het gebruiken + van Jis-codes -die ik later in deze text nog bespreek- die vry + onhandig zijn en in feite nooit voorkomen. In grafische modi + ka dit erg lastig zijn daar er dus karakters zijn met verschil + lende breedtes. De 'standaard' gebruiker zal echter aan locate + genoeg hebben. + + Jis en Shift-Jis. + Om het grote aantal tekens -Kanji, Katakana en Hiragana- uit + de Japanse taal in een computer te krijgen was een nieuw en + beter systeem nodig. De ascii set gaf immers maar ruimte voor + 256 tekens min 32 tekens voor de schermaansturig. Voor de Jap- + anse taal bij lange na niet genoeg. Er moest dus een nieuw 2- + byte systeem worden ontworpen waarmee dus 65536 tekens kunnen + worden opgeslagen. Na een aantal lange druilerige zondag mid- + dagen was men er uit in Japan. De Jis standaard vond het licht + en alles ging veranderen. 65536 tekens zou zelfs voor de Chi- + nese taal genoeg zijn, maar goed... Vrijwel alle mogelijk Kan- + ji uit de Japanse taal werden in het Jis-systeem opgenomen, + evenals alle Katakana en Hiragana, met accenten en zonder. + Maar zelfs toen hadden de heren nog ruimte over. In de Jis2 + standaard staan dus, "alle" Kanji, Katakana, Hiragana, de + Europese schrift-tekens, het arabische numerieke stelsel, de + Griekse schrift-tekens, russisch, oud latijns, dubbele getal- + len, dubbele letters, alle! mogelijke leestekens uit alle wet- + telijk erkende talen(NvdR: ook Ijslands?), "alle" valuta- + symbolen, "alle" symbolen van maten en eenheden, tekeningen! + voor educatieve software, de nodige symbolen van + telefoontjes, vliegtuigen enz, afkortingen van bv TEL, FAX, + No. enz..... Te veel om op te noemen -en toch deed ik dat + net-. In de meeste 2+en en in de Turbo-R zitten zo wel de + JIS1 als de JIS2. In alle DOS2 cartridges zit de JIS1.. + In totaal zit er in de Turbo een dikke 256K aan Jis + lettertjes wat genoeg is voor 8192 karakters, waarvan er + zeker zo'n 7000 gebruikt worden. Om deze enorme hoeveelheid + aan karakters te kunnen gebruiken zijn er 2 aanstuur-codes + in gebruik. JIS en SHIFT-JIS. Het verschil tussen die 2 is + nogal vaag maar het komt er op neer dat JIS meer iets van + een adres weg heeft en SHIFT-JIS meer een logische code is. + Een shift-jis code begint altijd met een getal hoger dan + HEX 80 gevolgd door een ander getal hoger dan HEX 20. Hoe + dit bij Jis zit weet ik niet echt. + In de praktijk werkt men meestal met Shift-Jis en de lul die + Jis heeft bedacht mogen ze van mij dan ook morgen ophangen.... + +WERKING ONDER BASIC + + Onder Basic kan men ook de gewenste kanji of kana op 't + scherm krijgen, maar natuurlijk niet door met een toets- + combinatie te werk te gaan. Na een _KANJI2 kan men op CTRL- + SPACE drukken wat onder in 't scherm een command line + oplevert. Op de plaats die normaal door de functie toetsen + wordt ingenomen staat nu een 2 de cursor waar men kan gaan + typen. De bedoeling van het geheel is dat in "Romaji" -dit + is naam voor japans geschreven op een fonetische manier- + de gewenste kanji in typen, alle let ter gre pen worden + indien mogelijk vertaald naar Hiragana -de naam van het + Japanse fonetische lettergreepschrift- en als het woord nu + herkend wordt zal de bijbehorende Kanji op het scherm worden + gezet. Omdat het Japans echter veel homofonen kent kan men + met de spatie echter kiezen uit alle kanji met die + uitspraak, niet ideaal maar het is een oplossing. Probeer + maar eens "MORI" in te typen, het Japans voor boom/bos. + Na het typen van "MO" zal "MO" vervangen worden voor het + Hiragana teken voor de klank MO en na het typen van de + "RI" zal ook "RI" vervangen worden door het hiragana teken + voor de klank "RI", heeft overigens iets weg van een + handgeschreven "Y". + Drukt men nu op de spatie dan zullen de Hiragana tekens + "MO RI" worden vervangen door een Kanji, welke dit zal zijn + weet ik ook niet uit m'n hoofd maar uiteindelijk moet er + een teken op het scherm komen dat wel wat weg heeft van + 3 "*" sterretjes, twee onder, een boven. Als na + het drukken op de spatie -net zolang tot het teken in beeld + is dat men zoekt- het juiste teken is gevonden kan men met + return het teken op de plaats van de eerste cursor krijgen. + Verder is het ook mogelijk om in het Europese-font uit de + Jis2 rom te typen. Na een druk op F-1 zulllen alle tekens + in JIS letters op het scherm komen waardoor mooie lettertjes + te verkrijgen zijn. Na een druk op return komen deze + prachtige 16*16 Europese letters op de plek van de eerste + cursor. Nog een druk op F-1 en deze stand wordt weer uit + gezet. + +KATAKANA + + Verder is er ook het wat bekendere Katakana. Dit schrift + wordt door de Japanners gebruikt om Engelse woorden in + Japanse tekens te schrijven. De werkwijze is hetzelfde als + bij de Kanji alleen drukt men na het typen van het hele + woord op F-2 zodat alle hiragana tekens vertaald worden + naar katakana tekens. Lukraak weg typen kan echter niet. + Het Japans kent maar een paar klanken zodat de Engelse + woorden meestal zwaar verminkt naar katakana vertaald + moeten worden. Zo zal "FutureDisk" vertaald moeten worden met + "Pyu tya Di su ku". Zie aan 't eind van deze text de tabel + met alle katakana klanken. Om uit de commandline te komen + volstaat een tweede druk op CTRL-SPACE, overigens soms "pakt" + de computer die toetsdruk niet gelijk. Gewoon nog een keer + drukken... Om uit een Kanji scherm te komen is _ANK het + commando. + +DE KATAKANA KLANKEN: + + A I U E O BA BI BU BE BO < De "H"-klank met accent. + KA KI KU KE KO PA PI PU PE PO < idem. + SA SI SU SE SO DA DI DU DE DO < De "T"-klank met accent. + TA TI TU TE TO ZA ZI ZU ZE ZO < De "S"-klank met accent. + NA NI NU NE NO PYA PYU PYO< "PI" + "Y" klank. + HA HI HU HE HO TYA TYU TYO< "TI" + "Y" klank. + MA MI MU ME MO + YA YU YO + RA RI RU RE RO + WA NN + + Dit klopt niet helemaal, de meeste uitspraken verschillen wel + iets van wat hier staat maar over het algemeen is het + makkelijker om dit aan te houden... + + Dat was het dan wel voor deze keer, ik neem aan dat de + brievenschrijver van een aantal disks geleden tevreden is. + De 2-plus heb ik nu een paar keer achter elkaar behandeld + en ik denk dat ik maar stop met de 2+ en weer even op + MSX 2 overstap omdat we geloof ik niet zo gek veel 2+ leden + hebben. Nou dat was 't wel, dus... See ya! + +Keizer... diff --git a/Future Disk/21/Ledjes.md b/future_disk/21/ledjes.md similarity index 100% rename from Future Disk/21/Ledjes.md rename to future_disk/21/ledjes.md diff --git a/future_disk/21/mcode_special_2.md b/future_disk/21/mcode_special_2.md new file mode 100644 index 0000000..d1dd743 --- /dev/null +++ b/future_disk/21/mcode_special_2.md @@ -0,0 +1,202 @@ + Ruud vervolgt deze speciale programmeercursus... + + + MCODE SPECIAL (2) + + We vervolgen waar we op FD #19 gebleven waren... + + Het DATAveld + + We hebben dus een veld van 16*13 blokjes, waaronder al dan + niet mijnen zitten. Wat moeten we nu precies van een blokje + weten: + + 1. Mijn of niet + 2. Al zichtbaar gemaakt of niet + 3. Op veilig gesteld of niet + 4. Aantal aangrenzende mijnen. + + De gegevens 1 t/m 3 zijn vragen, die met ja of nee beantwoord + kunnen worden: Per gegeven is 1 Bit genoeg (JA: Bit staat op 1; + Nee: Bit staat op 0). Het laatste gegeven is een getal tussen + de 0 en de 8: hiervoor zijn 4 bits nodig. + We hebben dus per veld genoeg aan 7 bits, dus zeker genoeg + aan 1 byte(8 bits). Om al onze gegevens te kunnen opslaan + wordt gebruik gemaakt van 16*13 bytes: het DATAveld + (label:DATA). Een byte in het DATAveld heeft de volgende + betekenis: + +bitnr. 7 6 5 4 3 2 1 0 + mijn zichtbaar vlag x aantal aangrenzende mijnen + + De bovenste nibble (4 bits) zijn de gegevens en de onderste + geeft het aantal aangrenzende mijnen aan. + De eerste byte in het DATAveld heeft betrekking op het + blokje linksboven in beeld op xco,yco:(0,0). + De tweede byte heeft betrekking op het blokje op + xco,yco:(16,0). De 16e byte heeft betrekking op het blokje + op xco,yco:(0,16) etc.. + + Om te kunnen laten testen of ons programma werkt vullen + we nu eerst een dataveld zelf met mijnen, zoals in + MINESW.GEN het geval is. + + +VULSCHERM (kopieren in MC) + + Deze routine vult het scherm aan de hand van het DATAveld + met de juiste blokjes. Het HL register is de Adrespointer: + deze geeft aan met welk adres in DATA gewerkt wordt. B is + een teller die telt hoeveel blokjes we gehad hebben. Telkens + als 1 blokje gedaan is worden zowel HL als B met 1 verhoogd. + De routine wordt herhaald tot B>16*13 geworden is: + het hele scherm is dan gevuld. + + + Voor het neerzetten van een blokje is de routine COPY + essentieel. Deze routine copieert een stuk uit het VRAM + (in ons geval een van de blokjes van Page 1) naar een + andere plaats in het VRAM, net als het basic commando COPY. + Net als bij SETPAL ga ik hier niet uitleggen hoe deze routine + precies werkt, maar vertel ik slechts wat je nodig hebt om + hem te gebruiken. In het HL regeister moet het adres staan + waar de gegevens staan die nodig zijn voor de COPY. In dit + geval is dit het adres BLOKDATA. Je ziet hier hieronder + hoe die gegevens eruit moeten zien. + + +BLOKDATA: ; gegevens voor het COPY commando +SX: DB 0,0 ; source xco (welke xco komt het + blokje vandaan) +SY: DB 0 ; source yco ( yco ) +SPAGE: DB 1 ; source page( pagina ) +DX: DB 0,0 ; destination xco + (welke xco moet het naar toe ) +DY: DB 0 ; yco +DPAGE: DB 0 ; page +LX: DB 16,0; lengte in x-richting +LY: DB 16 +OVERIGE: DB 0,0,0 +COMMANDO: DB #D0 ; plaats blokje m.b.v. snelle copy + +; p.s. vergelijk met in BASIC: +; COPY (SX,SY)-(SX+LX,SY+LY),SPAGE TO (DX,DY),DPAGE + + + Merk op dat voor de x-coordinaten 2 bytes gereserveerd zijn, + dit omdat een xco in screen 7 tussen de 0 en 512 ligt en dus + 2 bytes in beslag neemt. + Als screen 5 aanstaat staan er altijd nullen in de 2de byte + voor de xco. + + Omdat alle blokjes 16x16 groot zijn en alle gekopieerd worden + van Page 1(SOURCE YCO=0) naar Page 0, liggen veel gegevens + al vast. + Het kopieren van een blokje komt er nu nog op neer de + juiste SX,DX en DY in te vullen en dan m.b.v. + + LD HL,BLOKDATA + CALL COPY + + het eigenlijke kopieren uit te voeren. + + De VDP start na het geven van het COPY commando met het + kopieren, de Z-80 werkt echter gewoon door met zijn eigen + instructies! + De VDP is dus eigenlijk een soort co-prossesor. Pas hiermee + op: als het commando COPY wordt gegeven staat de COPY dus nog + niet klaar; dat kan soms onhandig zijn als je er zeker van + moet zijn dat een bepaalde COPY gebeurd is voordat je verder + gaat met de volgende Z-80 instructies (hier is dat niet het + geval). + Als je wilt wachten tot de VDP klaar is kun je de volgende + routine gebruiken. + +COPYREADY: LD A,2 + CALL VDPSTA ; lees statusregister 2 + RRA + JP C,COPYREADY ; de VDP is nog niet + klaar: wacht hier + RET ; klaar voor volgende copy. + + + Het invullen van de juiste SX betekent dat we moeten weten welk + symbool op deze plaats van het beeld staat m.a.w. we moeten in + het DATAveld kijken. + + Bit voor Bit wordt gekeken in het DATAveld m.b.v de volgende + routine: + +VULSCHERML: LD A,(HL) ; in A staan de gevgevens over + het blokje + BIT 5,A + JR NZ,VLAG + BIT 6,A + JR Z,ONZICHTBAAR ; maakt niet uit wat + eronder zit + BIT 7,A + JR NZ,MIJN + + AND %00001111 ; het blokjes is een getal + of leeg +GETAL: ADD A,A + ADD A,A + ADD A,A + ADD A,A ; *16 + LD (SX),A + JP SETDX + + De volgorde van het afgaan van de Bit's is niet willekeurig: + het is niet de bedoeling dat er een mijn neergezet wordt + terwijl het blokje nog niet eens zichtbaar was + Als geen van de bovenste Bits in de DATA aanstaat, moet er + een getal neergezet worden. + M.b.v. de AND %00001111 worden de bovenste Bit's van het + A-register op 0 gezet en de onderste niet verandert: in A + staat nu het getal dat aangeeft hoeveel mijnen er om het + blokje heen liggen. + Als het getal 0 is moet het blokje met SX=0 gekopieerd + worden. + Als het getal 1 is moet het blokje met SX=16 gekopieerd + worden. + Als het getal 2 is moet het blokje met SX=32 gekopieerd + worden. + Vandaar dat het getal met 16 vermenigvuldigd wordt om de SX + te krijgen. + + Wat er ook voor blokje afgedrukt wordt: uiteindelijk (als de + SX bepaald is) komt de MSX aan bij de volgende routine: + +SETDX: ; bereken aan de hand van B de destination xco en yco + LD A,B + AND %00001111 ; getal tussen 0 en 15 + ADD A,A + ADD A,A + ADD A,A + ADD A,A ; *16 + LD (DX),A + ; getal tussen 0..16..32..48..64....240 + LD A,B + AND %11110000 ; idem: wordt na 16* deze loop + met 16 verhoogd + LD (DY),A ; en vormt zo precies de + destination yco + + In deze routine wordt aan de hand van het nummer van het + blokje waarmee we bezig zijn berekent waar op het beeldscherm + dit blokje terecht moet komen. Kijk goed naar deze routine: + het is een vaak toegepast principe! Dit is alleen mogelijk + voor 16x16 blokjes (voor 8x8 valt wel iets soortgelijks te + bedenken) en dit is dan ook een van de redenen dat je als + programmeur de tekenaar altijd moet leren "in machten van 2" + te tekenen. + + SX,DX,DY en alle overige gegevens zijn nu ingevuld, dus het + blokje kan gekopieerd worden en de routine net zolang + herhaald tot het hele scherm vol is (merk op dit duurt een + fractie van een seconde voor 16*13=208 COPY's ). + + Maar dit was het helaas alweer voor deze keer. WE GAAN OP + FD #22 vrolijk verder met deze cursus... + + Ruud Gelissen diff --git a/future_disk/21/moonblaster_music_cursus_4.md b/future_disk/21/moonblaster_music_cursus_4.md new file mode 100644 index 0000000..a802ef6 --- /dev/null +++ b/future_disk/21/moonblaster_music_cursus_4.md @@ -0,0 +1,101 @@ +Jorrith probeert de mensen weer aan te zetten tot het maken van riedels... + + + MOONBLASTER CURSUS part IV + + Hartelijk welkom beste lezer, bij alweer de vierde + aflevering van de MB-cursus. Een korte dit keer, het is + tenslotte voor mij ook vakantie !! (Voor de enige lezer + (Koen), voor het controleren van taalfouten zal het toch + niet veel meer uitmaken of ik nu veel of weinig onzin te + vertellen heb). Ik heb vorige keer een aantal dingen + beloofd. Zo beloofde ik bijvoorbeeld om met deze cursus een + of meerdere muziekstukken op te bouwen. Helaas komt dat er + door tijdgebrek nooit van, dus moet je gewoon de muziekjes + (die je in ieder geval t/m #20 nog in MoonBlaster in kan + lezen) maar eens helemaal met behulp van MB uitpluizen (heb + je wat te doen als je je verveeld!). Ik weet het, belofte + maakt schuld, maar ik heb me al aan zoveel dingen schuldig + gemaakt dat dit beetje er nog wel bij kan! + + BASSss + + In deze aflevering wilde ik het basgedeelte van een + muziekstuk bespreken. Voor je begint is het wel zo + verstandig om een bas-instrument te selecteren (Electric + bass 1 of 3 zijn 2 van mijn favorieten). Ik zal de rest aan + de hand van wat losse tips duidelijk proberen te maken. Voor + de zoveelste keer: als je het niet snapt kun je altijd + contact opnemen met de redactie. Ik heb nog nooit iemand + iemand gehad die het niet snapte. Op zich erg vreemd, ik kan + me niet voorstellen dat ik alles zo goed uitleg. Sterker + nog, ik weet zelfs niet altijd wat ik bedoel met hetgeen ik + getypt heb... + + Om een lang verhaal kort te maken komen hier enkele tips: + + - Gebruik een (of meerdere) lage octaven. Mijn persoonlijke + favorieten zijn octaaf 2 en 3(NvdR: die van mij 1 & 8). + - Om een bas te maken die niet vals klinkt kun je het beste + een beetje de hoogte van de laagste noot van een accoord + aanhouden. Dit is een nogal ingewikkelde zin, dus ik zal + hem even uitleggen aan de hand van een voorbeeldje. + Stel: Je hebt het volgende ingevoerd in MB: + + Step: 01 02 03 04 05 06 07 08 + Ch.1: A 4 OFF A 4 OFF A 4 OFF A 4 OFF + Ch.2: C 5 OFF C 5 OFF C 5 OFF C 5 OFF + Ch.3: E 5 OFF E 5 OFF F 5 OFF E 5 OFF + + Om nu een goed klinkende bas te maken moet je een beetje de + laagste noot van het accoord aanhouden, in dit geval dus de + "A". Het zou er dan zo uit kunnen zien: + + Step: 01 02 03 04 05 06 07 08 + Ch.1: A 4 OFF A 4 OFF A 4 OFF A 4 OFF + Ch.2: C 5 OFF C 5 OFF C 5 OFF C 5 OFF + Ch.3: E 5 OFF E 5 OFF F 5 OFF E 5 OFF + Ch.4: A 2 OFF A 2 OFF A 3 OFF A 2 OFF + + - Bij een rustig nummer hoort een rustige bas. Laat daarom + relatief veel ruimte vrij tussen de verschillende noten. + - Bij een snel nummer precies het tegenovergestelde: veel + noten, maar ook weer niet teveel. Als je het hele + baskanaal vol zet ben je een beetje te enthousiast + geweest... + - Doe af en toe wat afwisseling in de bas, dit zorgt vaak + voor schitterende resultaten. + - Een bas die steeds hetzelfde blijft, terwijl de accoorden + veranderen kan mooie resultaten hebben. + - Het springen van een lager octaaf naar 1 octaaf hoger + klinkt vaak erg goed. Spring daarna wel weer terug, zodat + je dit spelletje -indien gewenst- nog eens kan herhalen. + + Dit was zo'n beetje alles. Valt mee he? Als je eenmaal de + accoorden onder de knie hebt is de rest echt niet meer zo + moeilijk. + + OEFENING BAART KUNST + + Een oud spreekwoord, maar het blijft gelden. Hoe meer je het + doet hoe beter je erin wordt. Overigens geldt ditzelfde ook + voor OPL4, alleen moet je dan de genoemde octaven verlagen, + omdat dit nu eenmaal iets anders werkt. Goede kandidaten bij + OPL4 zijn voor een rustig nummer Slap bass (1 of 2) en + Fingered bass, bij het wat ruigere werk is Picked bass of + Synth bass (1 of 2) aan te bevelen. + + A little present + + Op deze disk staan (onder voorbehoud) de drumvoorbeelden van + de vorige keer. Ze stonden er wel op, maar niet zoals het + hoorde... Ook staan er nog twee voorbeelden op met daarin de + tot nu toe besproken onderwerpen, nl. de bas, de accoorden + en de drums. Zo houdt ik me toch nog een beetje aan m'n + belofte!(NvdR: misschien komt dit allemaal wegens + diskruimte gebrek te vervallen; schrik niet als de zooi niet + op de disk staat) + + Een prettige vakantie allemaal ! + + Jorrith "Vakantiestress..." Schaap diff --git a/Future Disk/21/Recursie.md b/future_disk/21/recursie.md similarity index 100% rename from Future Disk/21/Recursie.md rename to future_disk/21/recursie.md diff --git a/future_disk/21/screen_12.md b/future_disk/21/screen_12.md new file mode 100644 index 0000000..4d146f8 --- /dev/null +++ b/future_disk/21/screen_12.md @@ -0,0 +1,75 @@ + Dhr. Keizer verheldert onze visie over screen 12 + + WHAT THE XXXX IS SCREEN12? + + ���� + ���� + ���� + ���� + + + Ik was een tijdje geleden bezig met de 2+ VDP. Omdat lang niet + alle omgebouwde 2-plussen ook 2 plusROMs hebben, mag dit dus + allemaal niet via de BIOS. De VDP direct aansturen dus. + Nu had ik eigenlijk geen flauw idee hoe dit allemaal moest + omdat ik geen data heb over de V9958. Dus, de telefoon maar + even gepakt, want dan ben je daar immer zo achter..... Niet + dus!!! Het aansturen van de V9958 schijnt echt een probleem + te zijn want zelfs de grote computer wizzzzkidzzz van MSX-end + Nederland konden me nog niet eens vertellen hoe ik screen 12 + aan moest zetten. Logisch was geweest om 12 in A (LD A,12) + en dan een call naar CHGMOD... NO ABSOLUTELY NOT! Waarom + weet ik niet maar dat was geloof ik een idee want er gebeurt + gewoon niets, maar wat dan wel?(NvdR: mijnheer Keizer, U + bent niet helemaal duidelijk meer) + Als eerst moet je blijkbaar screen 8 aanzetten, om daarna + "08" te zetten in register 25. Dus: + + SCRN12: LD A,08 + CALL CHGMOD + DI + LD A,08 + OUT ($99),A + LD A,128+15 + OUT ($99),A + EI + JP ?????? + + Dit kleine stukje source is genoeg om screen 12 aan te zetten + zonder dat er speciale 2+ BIOS routines worden gebruikt... + Om te kijken of er wel een V9958 aanwezig is, is het volgende + stukje source nodig: + + V9958?: DI + LD A,$01 + OUT ($99),A + LD A,$8F + OUT ($99),A + PUSH AF + POP AF + IN A,($99) + LD D,A + XOR A + OUT ($99),A + LD A,$8F + OUT ($99),A + EI + VDP-JP: LD A,D + AND $3E + JP NZ,V9938R + JP V9958R + + Dit stukje source kijkt dus ook echt alleen of er een V9958 is + zonder naar ROMS te kijken, iets dat veel programma's nog eens + willen doen. Een normale MSX2 met daarin dus een V9958 wordt + dus tot 2+ gebombardeerd door deze routine. Dat was 't wel, + verder moet je screen 12 als screen 8 behandelen en om overig- + ens screen 11 te krijgen moet je de "08" die je naar register + 25 out vervangen door "24", decimaal dus... + + Van wie ik deze wijsheid heb?? Lijkt me vrij duidelijk... + Van de MSX programmeur in Nederland, Alex Wulms. + + Well, good luck... I guess?!?! + +Tobias "Thank you Alex" Keizer diff --git a/future_disk/22/data_compressie_5.md b/future_disk/22/data_compressie_5.md new file mode 100644 index 0000000..bf42670 --- /dev/null +++ b/future_disk/22/data_compressie_5.md @@ -0,0 +1,1055 @@ + Jan-Willem bazelt weer over dingen die een simpele ziel als ik nooit zal begrijpen... + + Data Compressie 5 (?) + + Jaa, sorry hoor, maar ik ben de tel kwijt geraakt. Niet dat + er zoveel cursi waren, maar ik heb al een keer of 4 niks + meer gedaan, of beloofd dat ik de listing zou gaan + bespreken. Belofte maakt schuld, dus .... + + RUNLEN.GEN + + AL MIJN COMMENTAAR KOMT NU IN GROTE LETTERS. ZO ZIE JE HET + VERSCHIL TUSSEN COMMENTAAR EN LISTING MAKKELIJKER. + + WE STARTEN MET WAT COMMANDO'S VOOR DE ASSEMBLER (IN DIT + GEVAL GEN80). + +* g 0,s 15 + + HIERNA VOLGEN ENIGE COMMENTAAR REGELTJES.... + +; Runlength v3.0 1995 +; (c) Jan-Willem van Helden +; Thanks to: +; - Ivo Wubbels & Falco Dam +; - David Huffman +; - Lempel-Ziv Welch + +; de JCP file ziet er zo uit: + +; - codebyte1 (1) +; - codebyte2 (1) +; - x-offset (1) +; - y-offset (1) +; - paletbit (1) (als 0 geen palette) +; als palette=0: volgende 32 bytes palette +; daarna komt data + + IK BEGIN MET EEN KLEINE SETUP, DIE NODIG IS VOOR MSX-DOS. + HET IS ALTIJD HANDIG OM EEN MACRO TE EDITTEN VOOR DE BIOS + CALLS. + +bios: macro @bios1 + ld iy,(#fcc0) + ld ix,@bios1 + call #1c + endm + + EEN MACRO OM TEKSTEN AF TE DRUKKEN + +printaf: macro @printaf1 + ld de,@printaf1 + ld c,#9 + call #f37d + ld de,nexttext + ld c,#9 + call #f37d + endm + + OM DE RST20 TE SIMULEREN + +rst20: macro + ld a,h + sub d + jr nz,$+4 + ld a,l + sub e + endm + + NOG EEN MACRO DIE WE LATER NODIG HEBBEN + +searchtabel: macro + ld ix,tabel + ld iy,tabel+2 + ld b,-1 +;tabelsrc: + ld l,(ix+0) ;in HL de laagste + ld h,(ix+1) + ld e,(iy+0) ;in DE de hogere + ld d,(iy+1) + + rst20 + + jp c,$+7 ;DE hoger ?? -> nieuwe laagste + + push iy + pop ix +;--- + inc iy + inc iy + djnz $-26 + + push ix + pop hl + ld de,tabel + and a + sbc hl,de + and a + rr h + rr l + ld a,l + endm + + EEN LAATSTE AANTAL EQU'S + +bdos: equ #f37d +datfil: equ #8000 +regelv: equ 128 +tabel: equ #d000 + + ld a,(#f342) ; zet RAM op #4000 + ld h,#40 + call #24 + + ld hl,#5c ; zet de 2e filenaam in + ld de,fcb ; het File Control Block + ld bc,12 + ldir + + ld hl,#82 ; bekijk de rest van de + ld de,verwerking ; commandline + ld bc,#100-#82 + ldir + + ld hl,tabel ; vul de tabel met nullen + ld de,tabel+1 + ld bc,(256*2)-1 + ld (hl),0 + ldir + + ld e,"/" ; zoek naar de file options + ld hl,verwerking + call cmpr + call z,fndslash + + printaf starttext + + + ld de,free ; DMA op einde van de file + ld c,#1a ; zetten + call bdos + + ld de,fcb ; file openen + ld c,#0f + call bdos + or a + jp nz,endsequence ; error + + ld hl,0 + ld (blok),hl + ld (blok+2),hl + ld (#f3ea),hl + inc hl + ld (grote),hl + + ld a,(depacking) ; kijken of we soms moeten + and a ; uitpakken i.p.v. inpakken + jp nz,depacker + + printaf starttext1 ; nee hoor, we gaan inpakken + + ld hl,(filsiz) + call fulprt + + printaf decstr + + printaf savetext + + ld c,#1 ; kijken of we 'm moeten + call bdos ; inpakken of der mee + cp "s" ; moeten stoppen + jp z,loadpicture + cp "S" + jp nz,closefile + +; nu wordt het plaatje daadwerkelijk ingeladen + +loadpicture: + ld hl,(filsiz) + ld (fil_siz),hl + ld a,(screen) ; gekozen scherm aanzetten + bios #5f + ld a,(screen12) + inc a + jp nz,n_setscreen12 + ld bc,#819 ; screen 12 aan + bios #47 +n_setscreen12: + ld a,(#ffe7) ; sprites uit + or 2 + ld b,a + ld c,8 + bios #47 + ld de,#8000 ; dma op #8000 + ld c,#1a + call bdos + ld hl,4 ; eerste 4 bytes inladen + ld de,fcb + ld c,#27 + call bdos + +;kijken of het een .DAT/.GE5 file is + + ld a,(#8000) + cp #fe + jp nz,loadpicture_d ;dat file + ld hl,3 + ld de,fcb + ld c,#27 + call bdos + jp loadpicture_b ;bin file + + EEN DAT-FILE BEGINT ALTIJD MET DE X-LENGTE (2-BYTES) EN DE + Y-LENGTE. DEZE ZIJN GEGEVEN IN DOTS. OM ZE OM TE REKENEN + NAAR REEELE BYTES, ZIE HET VOLGENDE +(IN DE VOLGENDE TEXT!). + Jan-Willem bazelt weer over dingen die een simpele ziel als ik nooit zal begrijpen... + + Data Compressie 5 (?) + +(VERVOLG) + +loadpicture_d: + ld hl,(#8000) +; in geval van screen 5: delen door 2 +; 6: 4 +; 7: 2 +; 8: 1 + + ld a,(screen) + cp 8 + jp nc,loaddatloop2_1 + and a + rr h + rr l + cp 6 + jr nz,loaddatloop2_1 + and a + rr h + rr l +loaddatloop2_1: + ld a,l + dec a + ld (xofset),a ; mijn x-offset vullen + ld a,(#8002) ; y-offset bepalen + ld c,a + dec a + ld (yofset),a + ld hl,(vrmpnt) ; gelijk aan 0 + call loaddatfl ; blokje inladen +loaddatloop: + push bc + ld bc,(xofset) + inc c +loaddatloop2: + ld a,(de) ;werkelijke naar het + call putintable ;scherm toeschrijven + bios #177 + inc hl + inc de + push hl + ld hl,#c000 + rst20 + call z,loaddatfl + pop hl + dec c + jp nz,loaddatloop2 + ld hl,(vrmpnt) ; naar het begin van de + push de ; volgende regel + ld de,256 + ld a,(screen) ; opletten met die screens ! + cp 7 + jp nc,loaddatloop3 + ld de,128 +loaddatloop3: + add hl,de + ld (vrmpnt),hl + pop de + pop bc + dec c + jp nz,loaddatloop ; blijven doen totdat datfile + ; op het scherm staat + ld a,(nopaletdat) + inc a + jp z,loadpicture1 ; palet switch disabeled + ex de,hl + ld b,32 ; anders nog even het palet + ld de,palet ; inladen (kan alleen bij +paletdatl: ; dat files gemaakt door + ld a,(hl) ; DD-Graph. + ld (de),a + push de + inc hl + ld de,#c000 + rst20 + pop de + inc de + call z,loaddatfl + djnz paletdatl + + ld hl,palet ; paletje aanzetten. + call setpal + + jp loadpicture1 +loaddatfl: ; het daadwerkelijke laden + push bc ; van de dat-file + push hl + ld de,#8000 + ld c,#1a + call bdos + ld hl,#4000 + ld de,fcb + ld c,#27 + call bdos + ld de,#8000 + pop hl + pop bc + ret +; binaire files inladen + + BINAIRE FILES ZIJN EEN STUK MAKKELIJKER. JE HOEFT ALLEEN + MAAR TE LADEN TOT HET EINDADRES EN DAT NAAR HET VIDEORAM TE + DUMPEN. + +loadpicture_b: +;voor screen 5 geldt: 127 +; 6 127 +; 7 255 +; 8 255 voor de X-offset + ld a,(screen) + cp 7 + ld a,255 + jp nc,loadbinary + ld a,127 +loadbinary: + ld (xofset),a + ld hl,(screenlength) + ld (screen_length),hl + ld de,-#4000 +loadpicturel: + ex de,hl + ld de,#4000 + add hl,de + ex de,hl + push de + ld de,#8000 + ld c,#1a + call bdos + ld hl,#4000 + ld de,fcb + ld c,#27 + call bdos + ld hl,#8000 + ld bc,#4000 + pop de + push de + ex de,hl +loadpicture2: + ld a,(screen) + cp 7 + push de + ld d,h + ld a,211 + jr nc,loaddicture + and a + rl d ; keer 2 !!! +loaddicture: + cp d + pop de + ld a,(de) + call c,putintable + bios #177 + inc hl + inc de + dec bc + ld a,b + or c + jp nz,loadpicture2 + + ld hl,(fil_siz) + ld de,#4000 + and a + sbc hl,de + ld (fil_siz),hl + pop de + jp nc,loadpicturel + ld a,211 + ld (yofset),a + ld hl,(paletdata) ; palet nog binnenhalen + ld a,h + or l + jp z,loadpicture1 + ld de,palet + ld bc,32 + bios #59 + ld hl,palet + call setpal +loadpicture1: + call close_file_real + + BIJ HET INLADEN NET WERD PER BYTE DE ROUTINE PUTINTABLE + AANGEROEPEN. DEZE ROUTINE MAAKT EEN TABEL AAN MET DE + WAARDEN VAN HET AANTAL KEER VOORKOMEN VAN DE BYTE. ENKELE + CURSI TERUG HEB IK UITGELEGD, DAT JE OM EEN GOEDE COMPRESSIE + TE KRIJGEN DE MINST VOORKOMENDE BYTE ALS CODE-BYTE MOET + GEBRUIKEN. IN DE VOLGENDE ROUTINE DOEN WE DAT. ALS + UITBREIDING ZOEKEN WE OOK NOG EEN 2E CODE-BYTE. NU KUNNEN WE + ZOWEL IN 1 ALS IN 2 BYTE(S) CRUNCHEN + + +; nu wordt de minst voorkomende waarde gezocht + + searchtabel + ld (codebyte1),a + ld (ix+0),#ff ; die positie effe vullen + ld (ix+1),#ff ; (meest voorkomend maken) + +; nu wordt de een na minst voorkomende waarde gezocht + + searchtabel + ld (codebyte2),a + +; de codebyte is gevonden +; nu wordt alles klaargemaakt om het crunchen te beginnen + + ld hl,jwext ;die coole .JCP + ld de,ext + ld bc,3 + ldir + + xor a + ld (fcb),a ; defaultdrive + + ld de,fcb ; file aanmaken + ld c,#16 + call bdos + + ld hl,0 + ld (blok),hl + ld (blok+2),hl + inc hl + ld (grote),hl + +; create header + + ld a,(codebyte1) + ld (dma),a + ld a,(codebyte2) + ld (dma+1),a + ld a,(xofset) + ld (dma+2),a + ld a,(yofset) + ld (dma+3),a + + ld de,dma ; header wegschrijven + ld hl,4 + call crnstoreit + + ld a,(nopaletdat) ; palet storen ? + ld (dma1),a + ld de,dma1 + ld hl,1 + push af + call crnstoreit + pop af + inc a + jp z,nostorepal ; zo ja, dan zijn de + ; volgende 32 bytes paletdata + ld de,palet + ld hl,32 + call crnstoreit + + NU GEBRUIK IK WEER DIE SEMI PROGRAMMEER TAAL DIE OOK IN DE + VORIGE CURSI GEBRUIKT WERD. + +nostorepal: + ld hl,0 ; A + ld (vrmpnt),hl +crnrestart: + ld bc,1 ; CNTR=0 + bios #174 ; get A + ld d,a + xor #ff + bios #177 +crnloop: + call crnendline ; A+1 wordt geset in crnendline + ld a,(endfile) + and a + jp nz,crnstore + bios #174 ; get A+1 + cp d ; A=A+1 ? + jp nz,crnstore ; NO + xor #ff + bios #177 ; laat vooruitgang zien + inc bc + jp crnloop ; YEP +crnstore: + push hl + push de + ld h,b + ld l,c + ld d,0 + ld e,3+1 ; is CNTR > 3 ??? (nieuw idee) + rst20 + pop de + pop hl + jp nc,crnstore1 ; ja + ld a,(codebyte1) ; check of het 1 van de 2 + cp d ; codebytes is + jp z,crnstore1 ; ja, dan store ze als crunch + ld a,(codebyte2) ; data + cp d + jp z,crnstore1 + push hl ; zijn ze dat niet, schrijf + push bc ; dan het aantal keer de byte + ld b,c ; naar de disk + ld hl,dma1 +crnstore2: + ld (hl),d + inc hl + djnz crnstore2 + pop hl + ld de,dma1 + call crnstoreit + pop hl + ld a,(endfile) ; einde ? + dec a + jp z,closefile + jp crnrestart ; begin aan de volgende byte +crnstore1: + ld a,d + ld (dma+1),a ; STORE A + ld a,b ; A kleiner dan 256 ? + and a ; store dan maar 3 bytes + jp z,crnstore3bytes + ld a,(codebyte1) ; store codebyte + ld (dma),a + ld (dma+2),bc ; STORE CNTR + push hl + ld hl,4 +crnstore3: + ld de,dma + call crnstoreit ; STORE de hele heise + pop hl + ld a,(endfile) ; einde ? + dec a + jp z,closefile + jp crnrestart ; begin aan volgende byte +crnstore3bytes: + ld a,(codebyte2) ; schrijf maar 3 bytes weg + ld (dma),a + ld a,c + ld (dma+2),a + push hl + ld hl,3 + jp crnstore3 +crnstoreit: + push hl ; het wegschrijven + ld c,#1a + call bdos + pop hl + ld de,fcb + ld c,#26 + jp bdos +crnendline: + push bc ; routine om te bepalen of + push de ; we het einde van de regel + ld d,l ; bereikt hebben + ld a,(screen) + cp 7 + jp nc,nietdelen + ld a,d + sub 128 + jp c,nietdelen + ld d,a +nietdelen: + ld a,(xofset) + cp d + jp nz,crnendline3 + ld a,(screen) + ld hl,(vrmpnt) + ld de,256 + cp 7 + jr nc,crnendline2 + ld de,128 +crnendline2: + add hl,de + ld (vrmpnt),hl + cp 7 + ld d,h + ld a,(yofset) + jr nc,crnendline4 + and a + rl d ; keer 2 !!! +crnendline4: + cp d + jr nc,crnendline3_1 + pop de + pop bc + ld a,1 + ld (endfile),a + ret +crnendline3: + inc hl +crnendline3_1: + pop de + pop bc + ret +closefile: + xor a ; einde van het programma + bios #5f ; scherm 0 aan + ld hl,stndpalet ; standaard palet aan + call setpal +close_file: + call close_file_real ; file sluiten + ld c,0 + jp bdos ; exit met system-reset +close_file_real: + ld de,fcb + ld c,#10 + jp bdos + + IN DIT PROGRAMMA ZIT OOK GELIJK DE UITPAKKER. + + (LEES DIE IN TEKST(3))! + + Jan-Willem bazelt weer over dingen die een simpele ziel als ik nooit zal begrijpen... + + Data Compressie 5 (?) + +(VERVOLG VERVOLG) + +depacker: + printaf depacktext + + ld c,#1 ; kijken of we moeten uit- + call bdos ; pakken of stoppen + cp "d" + jp z,loaddepackdat + cp "D" + jp nz,closefile +loaddepackdat: + ld de,free ; dma op vrije plaats + ld c,#1a + call bdos + + ld hl,(filsiz) ; file laden + ld de,fcb + ld c,#27 + call bdos + + ld a,(screen) ; schermpje aan + bios #5f + + ld a,(free) ; data vullen + ld (codebyte1),a + ld a,(free+1) + ld (codebyte2),a + ld a,(free+2) + ld (xofset),a + ld a,(free+3) + ld (yofset),a + ld a,(free+4) + and a + ld de,free+5 + jp nz,nodepackpalet; palet checken + ld hl,free+5 + ld de,palet + ld bc,32 + ldir + ld hl,palet + call setpal + ld de,free+5+32 +nodepackpalet: ; de werkelijke depacker + ld hl,0 ; startadres in VRAM +depackrout: + ld a,(de) ; GET data + ld b,a + ld a,(codebyte2) ; data = CODEBYTE2 ? + cp b + jp z,depack1loop + ld a,(codebyte1) ; data = CODEBYTE1 ? + cp b + jp z,depackloop + ld a,(de) ; NO + bios #177 ; WRITE data TO VRAM + inc de + call crnendline ; endline ? + ld a,(endfile) ; einde ? + and a + jp nz,enddepack + jp depackrout ; volgende data +depackloop: + inc de ; GET A + ld a,(de) + ex af,af' + inc de + ld a,(de) ; GET CNTR + ld c,a + inc de + ld a,(de) + ld b,a +depack_loop: + ex af,af' + bios #177 ; DUMP A CNTR times + ex af,af' + call crnendline ; endline ? + ld a,(endfile) ; einde ? + and a + jp nz,enddepack + dec bc + ld a,b + or c + jp nz,depack_loop + ex af,af' + inc de + jp depackrout ; next data +depack1loop: + inc de + ld a,(de) ; GET A + ex af,af' + inc de + ld a,(de) ; GET CNTR (1 byte) + ld c,a + ld b,0 + jp depack_loop +enddepack: + ld c,#1 ; input ? + call bdos + jp closefile ; einde programma + + HET EIGENLIJKE PROGRAMMA IS NU GEDAAN. ALLEEN NOG ENKELE + SUB-ROUTINES VOLGEN + +putintable: ; tabel vullen + push de + push bc + ld b,a + inc b + ld ix,tabel-2 + ld de,2 +putintablel: + add ix,de + djnz putintablel + + ld c,(ix+0) + ld b,(ix+1) + inc bc + ld (ix+0),c + ld (ix+1),b + pop bc + pop de + ret +fndslash: ; zoeken naar de / + inc hl + ld a,"5" ; scherm bepalen + cp (hl) + jp z,scr5 + ld a,"6" + cp (hl) + jp z,scr6 + ld a,"7" + cp (hl) + jp z,scr7 + ld a,"8" + cp (hl) + jp z,scr8 + ld a,"1" + cp (hl) + jp z,scr12 +nextpart: + inc hl ; zoeken naar de P + ld a,"," + cp (hl) + ret nz + inc hl + ld a,"P" + cp (hl) + call z,nopaleton ; palet aan cq uit + ld a,"p" + cp (hl) + call z,nopaleton + inc hl + ld a,"," + cp (hl) + ret nz + inc hl + ld a,"D" ; depacker ? + cp (hl) + call z,depackon + ld a,"d" + cp (hl) + call z,depackon + ret + +; waarden goed vullen + +nopaleton: + ld a,-1 + ld (nopaletdat),a + ld de,0 + ld (paletdata),de + ret +depackon: + ld a,-1 + ld (depacking),a + ret +scr5: + ex de,hl + ld a,5 + ld (screen),a + ld hl,#7680 + ld (paletdata),hl + ld hl,128*212 + ld (screenlength),hl + ld a,128-1 + ld (xofset),a + ex de,hl + jp nextpart +scr6: + ex de,hl + ld a,6 + ld (screen),a + ld hl,#7680 + ld (paletdata),hl + ld hl,128*212 + ld (screenlength),hl + ld a,128-1 + ld (xofset),a + ex de,hl + jp nextpart +scr7: + ex de,hl + ld a,7 + ld (screen),a + ld hl,#fa80 + ld (paletdata),hl + ld hl,256*212 + ld (screenlength),hl + ld a,-1 + ld (xofset),a + ex de,hl + jp nextpart +scr8: + ex de,hl + ld a,8 + ld (screen),a + ld hl,0 + ld (paletdata),hl + ld hl,256*212 + ld (screenlength),hl + ld a,-1 + ld (nopaletdat),a + ld (xofset),a + ex de,hl + jp nextpart +scr12: + inc hl + ld a,"2" + cp (hl) + ret nz + ld a,-1 + ld (screen12),a + jp scr8 + +; ontzettend moeilijke en tegelijk zeer interessante routine ! + +beep: + bios #c0 + ret + +cmpr: + ld a,e + cp (hl) + ret z + inc hl + ld a,(hl) + and a + jp nz,cmpr + inc a + ret +endsequence: ; routine als er geen input + printaf endtxt ; is + ret + +; de texten + +endtxt: + db "Opts are: " + db "/n: MSX2/2+ screen number; /P: No palette" + db 10,13 + db "/D: depack file",10,10,13 + db "Default: A>RUNLEN filename /n,P,D$" +depacktext: + db "Press [D] to depack or any other key to quit" + db "$" +starttext: + db "Runlength V3.0",10,13,"$" +starttext1: + db 10,"File length: $" +savetext: + db 10,"Press [S] to save or any other key to quit" + db "$" +runlentxt: + db "RUNLEN" +nexttext: + db 10,13,"$" + +; variabelen + +verwerking: ds #100-#82 +screenlength: dw 0 +screen_length: dw 0 +depacking: db 0 +screen: db 8 +fil_siz: dw 0 +paletdata: dw 0 +palet: ds 32 +nopaletdat: db 0 +xofset: db 0 +yofset: db 0 +vrmpnt: dw 0 +stndpalet: dw 0,0,#611,#733,#117,#327,#151,#627 + dw #171,#373,#661 + dw #663,#411,#265,#555,#777 +screen12: db 0 +endfile: db 0 +codebyte1: db 0 +codebyte2: db 0 +dma: + +; Stukjes om weg te schrijven + + db 0 ; Codering + db 0 ; Gelezen waarde + dw 0 ; Countr waarde +dma1: ds 4 +jwext: db "JCP" +setpal: + push hl + ld bc,16 + bios #47 + pop hl + ld bc,#209a + otir + ret +ascbin: push de + push hl + ld hl,0 + ld (ascnum),hl + ld (ascnum+2),hl + pop hl +asclus: + ld a,(hl) + sub "0" + jp m,asceind + cp 10 + jp p,asceind + push hl + call maal10 + pop hl + inc hl + jp asclus +asceind: + pop de + push hl + ld hl,ascnum + ld bc,4 + ldir + pop hl + ret +maal10: + ld iy,(ascnum) + ld hl,(ascnum+2) + add iy,iy + adc hl,hl + ld e,l + ld d,h + push iy + pop bc + add iy,iy + adc hl,hl + add iy,iy + adc hl,hl + add iy,bc + adc hl,de + ld c,a + ld b,0 + add iy,bc + ld c,0 + adc hl,bc + ld (ascnum),iy + ld (ascnum+2),hl + ret + +ascnum: ds 4 + +fulprt: + ld de,decstr + ld b,7 + ld a,"$" +dc1: ld (de),a + inc de + djnz dc1 +dc2: xor a + ld e,a + ld b,16 +dc3: rl l + rl h + rl e + ld a,e + sub 10 + ccf + jr nc,dc4 + ld e,a +dc4: djnz dc3 + rl l + rl h + ld a,e + add a,"0" + push hl + ld hl,decstr+3 + ld de,decstr+4 + ld bc,4 + lddr + ld (decstr),a + pop hl + ld a,h + or l + jr nz,dc2 + ret +decstr: ds 7 + +fcb: db 0 +name: +inputfile: db "12345678" +ext: db "123" + dw 0 +grote: dw 0 +filsiz: ds 17 +blok: dw 0,0 +free: +einde: + end + + Zo, nu is dat hoofdstuk helemaal afgesloten. Volgende keer + gaan we eens aan de slag met Huffman. Niet zo moeilijk, + goede resultaten, maar erg traag voor de MSX. + + De bovenstaande listing staat op disk onder de naam + "RUNLEN.GEN" en is public domain. + + Zo, vaerdig ! + + Jan-Willem van Helden diff --git a/future_disk/22/moonblaster_music_cursus_5.md b/future_disk/22/moonblaster_music_cursus_5.md new file mode 100644 index 0000000..3a28f6e --- /dev/null +++ b/future_disk/22/moonblaster_music_cursus_5.md @@ -0,0 +1,324 @@ + Hehe die fuck cursus is bijna afgelopen... + + + MOONBLASTER CURSUS + + The semi-final part + + + Degenen die deze cursus al van begin af aan volgen + herinneren zich misschien nog de uitleg van een zekere + Stefan Boer(NvdR: Wie?). Hij zou mij nog een tekst sturen + over de accoorden. Half Augustus werd deze belofte eindelijk + een feit, zodat jullie alsnog de beloofde informatie krijgen. + + Nog een stukje citaat uit de begeleidende brief: "Met behulp + van een beetje muziektheorie wordt zelf muziek maken veel + makkelijker, omdat je dan veel eerder ziet welk accoord of + welke bas ergens bij past en welke noten ergens bij kunnen + zonder dat het vals wordt." Zo, nou hoor je het ook eens van + iemand anders, stelletje wijsneuzen! + + De rest van deze tekst is gewoon letterlijk overgetypt + (waarom hij de tekstfile niet heeft meegestuurd is me ook + een raadsel), dus voor commentaar ben je bij mij aan het + verkeerde adres. Het woord is aan Stefan. + + ACCOORDEN + + Accoorden zijn drie- of vierklanken. In de paragraaf over + begeleiding zal ik uitleggen hoe u accoorden in uw + muziekstukken kunt gebruiken. Maar nu eerst de opbouw van + een accoord. + + De grondtoon is de toon waaraan het accoord zijn naam + ontleent. Voor het C-accoord is dat dus de C. Het "normale" + of majeur accoord bestaat verder uit de 3e(NvdR: terts) en + 5e (kwint) toon uit de majeur toonladder van de grondtoon. + Dat klinkt heel ingewikkeld, maar het valt best mee. De + C-toonladder kent iedereen: + + C D E F G A B C + do re mi fa sol la ti do + + Het C-accoord is dus opgebouwd uit de grondtoon C, de derde + toon E en de kwint (vijfde toon) G: C-E-G. + + Alle toonladders: [niet echt "alle] + ------------------------------------------------------------- + C D E F G A B C C-toonladder + C# D# F F# G# A# C C# Cis/Des-toonladder + D E F# G A B C# D D-toonladder + D# F G G# A# C D# E Dis/Es-toonladder + E F# G# A B C# E F E-toonladder + F G A A# C D F F# F-toonladder + F# G# A# B C# D# F# G Fis/Ges-toonladder + G A B C D E G G# G-toonladder + G# A# C C# D# F G# A Gis/As-toonladder + A B C# D E F# A A# A-toonladder + A# C D D# F G A# B Ais/Bes-toonladder + B C# D# E F# G# B C B-toonladder + ------------------------------------------------------------- + + N.B. ik heb hier dezelfde notatie gebruikt als in + MoonBlaster, omdat er geen mol in de karakterset zit. Een A# + is dus hetzelfde als een Bes. Als u in MoonBlaster dus een + As nodig hebt, gebruik dan een Gis. + + Voorbeelden: + + 1) Dis accoord + 2) Bes accoord + 3) F accoord + 4) B accoord + 5) E accoord + + 1) Dis-G-Ais + 2) Bes-D-F + 3) F-A-C + 4) B-Dis-Fis + 5) E-Gis-B + + VARIATIES VAN ACCOORDEN + + Behalve het gewone accoord kom je ook veel accoorden met + toevoegingen tegen. Bijvoorbeeld C6, Fm, G7, Dm6, Am7, C+, + Fmaj7(NvdR: Dsus4, Dsus2). + + Een overzicht: + + C6 Dit is het C-accoord, echter met nog een "zesde" toon + eraan toegevoegd. Die zesde toon ligt drie halve + toonafstanden onder de grondtoon. Voor de C is dat + dus de A. Het C6 accoord wordt dus: CEGA + Fm Dit is een F-mineur accoord. De derde toon wordt met + een halve toon verlaagd. De A wordt dus As: F-As-C. + G7 Dit is een G-septiem accoord. Er komt nog een + "zevende" toon bij. De septiem-toon ligt twee halve + toonafstanden onder de grondtoon. Dat is voor het + G-accoord de F: G-B-D-F + Dm6 Dit is een combinatie van D6 en Dm. Het wordt dus: + D-F-A-B. + Am7 Dit is een combinatie van Am en A7. Het wordt dus: + A-C-E-G. + C+ Dit is een zogenaamde overmatige drieklank. De kwint + wordt met een halve verhoogd. Het C+ accoord luidt + dus: C-E-Gis. + Fmaj7 Aan het F-accoord wordt nog een toon toegevoegd, die + een halve toonafstand onder de grondtoon ligt. Het + F-accoord wordt dus F-A-C-E. + + Met een halve toonafstand wordt de afstand tussen twee + toetsen bedoeld. Dus de afstand tussen E en F of de afstand + tussen Fis en G. + + Voorbeelden: + + 1) C7 6) B7 + 2) Bes6 7) Esm7 + 3) Cmaj7 8) D7 + 4) Gm7 9) Fmaj7 + 5) Em 10) A6 + + 1) C-E-G-Bes 6) B-Dis-Fis-A + 2) Bes-D-F-G 7) Es-Ges-Bes-Des + 3) C-E-G-B 8) D-Fis-A-C + 4) G-Bes-D-F 9) F-A-C-E + 5) E-G-B 10) A-Cis-E-Fis + + + GRONDLIGGING + + De hierboven behandelde volgorde van tonen van een accoord + heet de grondligging. De accoorden hoeven niet perse in deze + volgorde te staan. U kunt ook de hoogste toon naar onder + halen of de laagste toon naar boven. Het F-accoord wordt + bijvoorbeeld vaak afgespeeld als A-C-F. + + + ACCOORD MET MINDER TONEN + + U kunt van een vierstemmig accoord een driestemmig maken + of van een driestemmig een tweestemmig door de kwint weg te + laten. + + U kunt van een vierstemmig accoord geen tweestemmig accoord + maken zonder dat u iets weglaat (dus Em7 wordt of E7 of Em). + U kunt dan zelf kiezen wat het beste klinkt. + + Dit kannodig zijn omdat u soms niet genoeg kanalen heeft. + Als u bij MoonBlaster bijvoorbeeld 3 kanalen voor de melodie + nodig heeft en 1 voor de bas, dan heeft u maar 2 kanalen + over voor de accoorden. + + M.D.A. + + (jawel jawel) + Stefan Boer + + + Nog een paar opmerkingen achteraf: ik heb hier maar een + paar wijzigingen in aangebracht (SoundTracker vervangen door + MoonBlaster, en een gedeelte m.b.t. bladmuziek + overschrijven. Deze tekst is voor de rest gewoon zoals ik + hem kreeg. Voor commentaar over deze tekst ben ik dus niet + bereikbaar :-) + (NvdR: en Stefan ook niet, want die zit op dit moment Japanse + meisjes te versieren. Okay, maybe not) + Eindelijk het laatste deel van die rotcursus van Jorrith! + + +MoonBlaster cursus - Final Part + + + Jaaahhh, geachte fans, alweer het laatste deel van de + MoonBlaster cursus. In deze cursus wilde ik als laatste + onderdeel de melodie behandelen, en geef ik als afsluiting + nog wat handige tips. Misschien nog wel meer, maar dat kan + ik nu nog niet zeggen (ik zit pas aan het begin van deze + tekst). Lees maar gewoon, dan merk je het vanzelf... + + De melodie + + De melodie is het belangrijkste onderdeel van een + muziekstuk. Zonder een melodie is een muziekstuk meestal + saai (hoeft niet natuurlijk, dat ligt aan jezelf). Zelf heb + ik me nog nooit echt intensief bezig gehouden met het maken + van een goede melodie. Daar heb je als redactielid of geen + tijd voor of geen zin in. + Maar om het kort te houden geef ik, net zoals in de vorige + afleveringen een soortement richtlijnen, en wie weet kun je + d'r wat mee... + + - Wijk niet teveel af van het accoord/ de accoorden die op + hetzelfde moment spelen. Hiermee bedoel ik dus: als je een + accoord hebt (bv. A 4 - C 5 - E 5), ga dan niet eigenwijs + zitten doen door een D of een B af te spelen, want meestal + klinkt dat gewoon niet. Als je het accoord zou veranderen + in bv. A 4 - B 4 - D 5, dan kan het natuurlijk weer wel, + maar dan zal een C of een E vaak niet mooi klinken. + Natuurlijk is het ook wel handig om in een muziekstuk vaak + van accoord te wisselen. + - Als je de achtergrond voor een muziekstuk eenmaal af hebt + (dus de drums, de bas en de accoorden) kun je dit gewoon + afspelen en ondertussen een melodie bedenken. Zelf doe ik + dit echter nooit, maar misschien heb je er wat aan. + - Als je eenmaal een mooie melodie in je kop hebt zitten + kun je, als het niet klinkt met de accoorden, twee dingen + doen. Of je verandert de melodie, of de achtergrond (de + bas en de accoorden). Bij mij komt het echter meestal op + het eerste neer... + - Een melodie waarin je weinig lege ruimtes hebt is vaak + niet mooi. Als je een heel druk muziekstuk wilt maken is + dit echter wel de beste methode, en als je de versterker + flink hard zet ben je ook gelijk van je buren af! + - Bij een rustig nummer moet je geen schelle instrumenten + gebruiken, bij een wat ruiger nummer echter juist wel. + - Als je eenmaal een achtergrondje hebt gemaakt kun je + hierin ook wijzigingen maken, zodat je een mooie overgang + van de ene melodie krijgt naar de andere. Laat bv. de + drums eens weg, of de bas (of vervang ze). + + Zo, dit was het wel zo'n beetje wat betrefd de melodie. + Natuurlijk blijft gelden: OEFENING BAART KUNST(en soms + kinderen). Als je je er echt serieus mee bezig wilt houden + moet je gewoon blijven klooien, het wordt vanzelf beter. + Noten kunnen lezen is niet nodig, en raak niet in paniek + als het niet lukt (anders krijgen wel allemaal half-maffe + leden die hun abonnement niet kunnen verlengen....). + + En toen kwam de rest... + + Tja, als opvulling kan ik alleen nog maar wat kleine tips + geven. Het is niet anders, maar aan alles komt nou eenmaal + een eind, dus ook aan deze cursus. Ik heb jullie nu alweer + genoeg verveeld, dus ga ik maar snel weer verder met 'the + technical stuff'. + +Tip 1: + + Als je een muziekstuk aan het maken bent, en je komt + patterns of noten tekort dan kun je het volgende doen. Bij + een pattern-tekort moet je het tempo zo verlagen dat de + snelheid precies 2x zo laag is. De 'formule' geef ik straks + wel, eerst het nut. Als je met een langzaam muziekstuk bezig + bent (en je hebt tussen de noten onderling nog (minstens) ��n + lege ruimte) dan kun je de helft van de patterns besparen + door alle noten naar boven te verhuizen. Er kunnen dan de + noten van 2 patterns op de ruimte van een pattern. Omdat dit + dan 2x langzamer afgespeeld wordt, duurt het muziekstuk dan + net zo lang, alleen heb je dan extra patterns over. Dit + werkt echter niet als de noten elkaar al direct opvolgen. + Bij OPL4 maakt dit niet zoveel uit, omdat je dan toch zoveel + kanalen hebt, zodat je de informatie uit een kanaal over 2 + kanalen kunt verdelen. + Het tegenovergestelde is ook mogelijk. Stel, je hebt te + weinig ruimte om alle noten te plaatsen die je wilt + plaatsen. Je wilt dus als het ware in het huidige tempo een + halve noot invoeren (bv. tussen step 7 en 8). Dit is te + verhelpen door het tempo 2x sneller te maken, zodat de data + van 1 pattern over 2 verspreidt kan worden. En nu werkt het + wel.... + Als afsluiting van deze tip nog even de formule: + + 25 - huidig tempo = een uitkomst (nee maar!) + + Als je het tempo 2x zo snel wilt hebben moet je deze waarde + delen door 2 (2x zo langzaam is vermenigvuldigen met 2). + Hieruit krijg je weer een bepaalde uitkomst, die je van 25 + af moet trekken om het gewenste resultaat te krijgen. Bv. + tempo 19 2x zo snel maken: 25-19=6. 6/2=3. 25-3=22. + +Tip 2: + + Als je gemaakte muziekstuk te kort is kun je dit heel erg + makkelijk rekken door bv. hetzelfde stuk nog eens af te + spelen zonder de melodie en (naar keuze) bas en/ of drums. + +Tip 3: + + Het maken van een muziekstuk gaat het makkelijkst als je + eerst een achtergrondje maakt met drums, bas, accoorden en + evt. special effects. Hierna hoef je alleen nog maar een + melodie toe te voegen, en klaar is Keessie ! + + +Tip 4: + + Je kunt een muziekstuk mooier maken als je tegelijkertijd + met het gewone achtergrondje ook een "pingel" laat meelopen. + De toonhoogte van deze pingel kun je het beste af laten + hangen van het accoord dat dan speelt. Een wel heel simpel + voorbeeld van een pingel: A 4 C 5 E 5 C 5. Natuurlijk zijn + er veel mooiere varianten denkbaar. Voor de pingel moet je + niet teveel afwijken van de noten van het accoord. + +Tip 5: + + Voor bijna alles uit deze (en voorgaande) afleveringen geldt + het volgende: het klinkt vaak mooi als je af en toe een + beetje variatie toebrengt door bepaalde noten ��n octaaf te + verhogen. + + Game Over + + Er zijn zo natuurlijk veel meer handige dingen te verzinnen, + maar ik heb geen zin om alles maar voor te kauwen, daar + wordt een mens maar lui van. Er is nog wel genoeg uit te + zoeken in de wondere wereld van MSX-muziek, maar dat moet je + dan zelf maar doen.... + + Dit is dan ook gelijk de afsluiting van deze MB-cursus. Alle + resultaten (waarschijnlijk geen) van deze cursus en eigen + probeersels zijn natuurlijk van harte welkom bij onze + FD-music contest (meer hierover in de Diversen-afdeling). + Als je onverhoopt nog vragen hebt (of wat anders) kun je me + bereiken op het volgende adres: + + Jorrith Schaap + Erasmusweg 7 + 9602 AB Hoogezand + Tel: 05980-27379 + + +Jorrith Schaap diff --git a/future_disk/23/mcode_special_3.md b/future_disk/23/mcode_special_3.md new file mode 100644 index 0000000..f8f6041 --- /dev/null +++ b/future_disk/23/mcode_special_3.md @@ -0,0 +1,256 @@ + + MCODE SPECIAL (3) + + + We gaan verder waar we op FD #21 waren blijven steken... + + +MAIN (het hoofdprogramma) + + Eigenlijk is dit de routine waaraan je het beste kunt + beginnen te programmeren. + Zorg dat de MAIN routine niet te lang wordt (zodat je hem in + ieder geval nog in 1 keer op het scherm kun krijgen) en zet + hier ook alleen de belangrijkste zaken in. + Je kunt dit bereiken door van elke onderdeel een CALL te + maken. Het is in het begin vaak al mogelijk om te zeggen wat + voor routines later in de hoofdroutine aangeroepen zullen + worden. Zet in de hoofdroutine dan alvast de CALL's klaar, + maak alvast de LABEL's aan maar zet op de plaats waar later + de eigenlijke routine komt een RET: dit bevordert het + overzicht, en bovendien blijf je op de hoogte van wat je + nog programmeren moet. De routine MAIN spreekt verder voor + zich: + +MAIN: + CALL SETSPRITES ; zet de sprites op goede coord. + EI + HALT + HALT + XOR A ; spatie balk ? + CALL GTTRIG + AND A + CALL Z,GEDRUKTQ ; misschien wel vuurknop + CALL NZ,GEDRUKT ; op knop gedrukt: maak zichtbaar + LD A,3 ; 2de knop ? + CALL GTTRIG + AND A + CALL Z,SHIFTQ ; misschien wel op shift + CALL NZ,VEILIG ; maak veilig + CALL BESTUUR ; besturingsroutines + CALL TESTEIND + LD A,7 + CALL SNSMAT + AND %00000100 ; escape + JP NZ,MAIN +EINDE: + XOR A + JP #5F + + Zoals je ziet kan met ESCape het spel afgebroken worden: dit + is een van de opties die je er het eerst in moet bouwen, + zodat je altijd uit het spel kan en kan controleren (als je + een programmeer fout maakt en de computer niets meer doet) of + je met ESCape nog weg kunt en het programma dus nog in de + hoofdlus rondliep. + + De spatiebalk en de linkermuisknop moeten er beide toe leiden + dat GEDRUKT aangeroepen wordt. Je test nu eerst op een van + beide (hier de spatiebalk) en als deze niet ingedrukt wordt + ( AND A levert zero ) test je in een aparte loop of de + linkermuisknop wel ingedrukt werd (GEDRUKTQ) + +GEDRUKTQ: + LD A,1 + CALL GTTRIG + AND A + RET + + p.s. de Q in sommige labels heeft voor mij de betekenis van + een ?, aangezien GEN80 labels met een ? niet aankan. + p.s.s. je ziet ook dat achter elk label een : geplaatst is. + Dit om het zoeken naar labels m.b.v. de TED-zoekfunctie + te vergemakkelijken, omdat je de aanroepplaatsen van + de labels niet tegenkomt. + + In de hoofdlus zitten ook nog 2 HALT's. + Deze zijn bedoeld om het geheel soepeler te laten verlopen. + Een hoofdlus zonder HALT duurt niet elke keer dat hij + doorlopen wordt even lang, b.v. omdat soms wel en soms niet + op een toets gereageerd moet worden. Dit heeft tot gevolg + dat b.v. de muisbesturing niet altijd even vaak per seconde + uitgevoerd wordt en de muis dus niet soepel loopt. + Zet daarom (als het even kan) altijd een of meerdere HALT's + in de hoofdlus. Het is verstandig om deze vooraf te laten + gaan door het commando: EI. + + Verder worden in de hoofdlus de routines BESTUUR en TESTEIND + altijd aangeroepen. VEILIG en GEDRUKT alleen als er op een + knop gedrukt wordt. De hooflus moet nooit te ingewikkeld + worden, anders verlies je het overzicht van het verloop van + het spel. + +BESTUUR + + In de routine BESTUUR wordt eerst de muis uitgelezen door + een aanroep van de subroutine MOUSE. + Je ziet in deze routine hoe dat er getest kan worden of er + een muis aangesloten is. + + M.b.v. de biosroutine GeTPAD worden in de adressen + #FAFE en #FB00 de verandering van de respectievelijk xco + en yco gezet. De inhoud van deze adressen wordt dan opgeteld + bij de huidige xco en yco van de 2 sprites, die staan op de + adressen aangeduid door de labels XCO en XCO+4(of YCO en + YCO+4) in de sprite-attribuuttabel. Zoals je ziet worden + hier nog niet deze attributen in het VRAM gezet, dat + gebeurt pas als in de hoofdlus opnieuw een CALL SETSPRITES + gebeurt. + Bovendien wordt m.b.v. het uitgebreid behandelde CP-commando + getest of het pijltje zich nog binnen de grenzen van het + beeld bevindt. + + Als de muisbesturing afgehandeld is, wordt gekeken of er + met de cursortoetsen of joystick bewogen wordt. + In het label SPEED staat hoeveel pixels er per druk op een + cursortoets verschoven wordt. + Normaal staat hierin 2 maar als de GRAPH-toets ingehouden + wordt, wordt dit getal 4. + + De Biosroutine GTSTCK levert de beweegrichting van cursor + of joystick. Aan de hand van deze waarde wordt bepaald welke + richtingsroutine aangeroepen wordt. + + Let er op dat voor een beweging in een diagonale richting + gewoon gebruik gemaakt wordt van de 2 bijbehorende + horizontale en vertikale richtingsroutines. + + Over de BESTUUR routine wil ik verder niet teveel uitwijden, + omdat deze niet bijster interessant is. Ik moet toegeven dat + ik bijna altijd als ik in een programma een besturings- + afhandeling nodig heb, ik deze routine (met enige aanpassing + van bv. de randcoordinaten) gebruik, omdat ze toch al zo + efficient mogelijk in elkaar zit. + Als je wil mag je gerust deze routine gebruiken in je eigen + programma's. Opnieuw programmeren is tijdsverspilling! + +LEES VERDER IN DEEL (2) + + MCODE SPECIAL (3) + + part 2 + + + +GEDRUKT (het spel zelf) + + We hebben nu een pijl, een veld met blokjes, besturingsroutines + en kunnen de knoppen uitlezen maar het spel zelf draait er + voornamelijk om dat er blokjes zichtbaar gemaakt kunnen worden. + De routine GEDRUKT regelt dit. + + GEDRUKT begint al meteen met een aanroep van een andere + routine: HAALBLOKNR. + + HAALBLOKNR zoekt uit op welk bloknr. het pijltje staat, + tevens worden DX en DY, de coordinaten waar naar toe straks + het blokje gekopieerd gaat worden al goed gezet. + +HAALBLOKNR: + LD A,(XCO) + AND %11110000 ; omlaag afronden + LD (DX),A ; wordt de plaats waar + een blok komt + RRCA + RRCA + RRCA + RRCA ; delen door 16: + het bloknr door xco + LD B,A ; even bewaren + LD A,(YCO) + AND %11110000 ; omlaag afronden + LD (DY),A ; is tevens bloknr. + door yco + ADD A,B ; optellen levert het + echte bloknr. + RET + + + In A staat nu het bloknummer, dit is dus de plaats in het + dataveld waarop gedrukt werd en die de speler van het spel + graag zichtbaar wil maken. Wij moeten nu laten zien wat er + op die plaats staat en hierop zonodig reageren. + Met de volgende routine komen erachter wat de gegevens (zie + bespreking DATAveld) zijn over het blokje waarop gedrukt + werd. + + + LD HL,DATA + LD C,A + LD B,0 ; nu in HL het DATA- + blokje, waarop je + ADD HL,BC ; met je pijlje hebt + gedrukt. + LD A,(HL) ; in A de inhoud van + je blok + + Bit voor bit wordt nu afgegaan wat die data voorstelt: + + BIT 5,A + RET NZ ; drukken op een vlag + heeft geen zin + BIT 6,A + RET NZ ; op een zichtbaar + blokje ook niet + BIT 7,A + JP NZ,DOOD ; op een mijn gedrukt + AND %00001111 + JP Z,CLEARDATA ; op een leeg hokje + + Een RET be�indigt de routine GEDRUKT, omdat deze met een + CALL aangeroepen wordt. Als je op een leeg hokje drukt wordt + doorverwezen naar een nieuwe routine, die de omgeving + automatisch zichtbaar gaat maken: CLEARDATA. Hierop ga ik + later in. Verreweg de meeste keren zal een speler drukken + op een getal dan moet het blokje zichtbaar gemaakt worden. + De hiervoor gegeven routine wordt dan gewoon doorlopen en + de computer komt aan bij de volgende routine: + +MAAKZICHTBAAR: + SET 6,(HL) ; in DATA aangeven + dat dit blokje al + LD HL,AANTALZICHTBAAR; zichtbaar is + INC (HL) + + Het aantal zichtbare hokjes wordt geteld, omdat we dan + eenvoudig kunnen nagaan of alle blokjes zichtbaar zijn. + Bovendien wordt in de data aangegeven, dat dit blokje nu + zichtbaar is zodat, als er nog een keer op dit blokje + gedrukt wordt, de computer niet meer reageert. + In het A register staan nu nog steeds de 4 onderste bit's + van de DATA. Dit is het getal wat afgedrukt moet worden. + Net zoals dit in de routine vulscherm gebeurde wordt de + Source Xcoordinaat als volgt berekend: + + ADD A,A + ADD A,A + ADD A,A + ADD A,A ; *16 bereken SX + LD (SX),A ; DX en DY al in + HAALBLOKNR gezet. + + DX en DY zijn al berekent, de rest van de gegevens ligt + vast --> met de volgende regels wordt het blokje + daadwerkelijk neergezet: + + LD HL,BLOKDATA ; laat ook zien waarop + gedrukt is + JP COPY ; einde GEDRUKT + + Na deze JP COPY wordt weer teruggekeerd naar de hoofdlus. + + Maar genoeg voor deze keer! De cursus gaat weer verder op de + volgende FD! Veel succes met programmeren! + +Ruud Gelissen + diff --git a/future_disk/24/2+_schermen.md b/future_disk/24/2+_schermen.md new file mode 100644 index 0000000..de06fab --- /dev/null +++ b/future_disk/24/2+_schermen.md @@ -0,0 +1,149 @@ + Ons aller lieve Tobias behandelt nog een keertje de MSX 2+ schermen .....stof voor de programmerende MSX 2+ freaks dus.... + + NOGMAALS: DE 2+ SCHERMEN. + + ���� + ���� + ���� + ���� + + + + Ik weet dat ik dit onderwerp al een keer eerder hab behan- + deld, maar bij gebrek aan andere onderwerpen toch nog maar + een keer de 2+ schermen. + + Ken je ze nog, de oude dagen waarin men net de 2+ over had + laten vliegen uit Japan; zonder handleiding uiteraard want + dan weegt het immers te veel. Daar komt nog eens bij dat de + handleiding geheel meestal in "onleesbare" Japanse "kriebels" + was zodat deze geen waarde had. Alles zelf uitzoeken was dus + het gevolg, en dan bleek al gauw dat de 2+ schermen + onhandelbaar waren. + In de oude dagen ja, want bij betere analyse blijkt namelijk + dat het allemaal nog wel meevalt, vooral screen 11 blijkt + helemaal niet zo onhandelbaar. Dat het allemaal wat meer + moeite kost, dat is wel zo... + +IN BASIC + + Deze idee�n waren natuurlijk toch wel ergens op gebaseerd, + in basic is er namelijk weinig mogelijk op de 2+ schermen. + COPY's en dergelijken gaan over het algemeen wel, maar + tekenen wordt toch een stuk moeilijker. Alleen met welgemik- + te VPOKE's is er het een en ander mogelijk. + In machinetaal is, mede door de hogere snelheid, al een stuk + meer mogelijk, en bij de juiste behandeling van de 2+ + schermen blijkt het allemaal toch nog mee te vallen. + +SCREEN 10 + + Dit is toch wel het meest gebruikte 2+ scherm in BASIC, des + te groter zal de verassing zijn als ik vertel dat dit scherm + helemaal niet bestaat. SCREEN 10 is een niet bestaande modus + die speciaal voor BASIC gemaakt is. De grap zit em namelijk + in het feit dat dit gewoon SCREEN 11 is maar door de BASIC + interpreter op een speciale manier wordt behandeld. Daardoor + zullen commando's als LINE en CIRCLE in SCREEN 10 wel goed + gaan. Verderop in deze tekst zal ik hierop terugkomen. + + +SCREEN 11 + + Zoals gezegd de eigenlijke modus van SCREEN 10. Dit scherm + bezit over een totaal aantal kleuren van 65536. Hoe ASCII ooit + aan die 12499 is gekomen weet ik niet, maar blijkbaar kunnen + ze beter programmeren dan tellen. Er worden per pixel 16 bits + gebruikt en bij mij levert dit nog altijd 65536 mogelijkhe- + den op als je zwart mee mag rekenen. In SCREEN 11 is, behalve + met welgemikte COPY's en VPOKE's, weinig spannends te doen. + Ook de VPOKE's zijn eigenlijk al alleen interressant in + ASSEMBLY omdat BASIC hier eigenlijk te sloom voor is. + + +SCREEN 12 + + Hier worden er 17 bits per pixel gebruikt wat 131072 kleuren + oplevert. Ook hier komt ASCII weer met een of ander vaag ge- + tal, dit keer 19268, maar ook daar klopt volgens mij geen + flikker van. Ook voor SCREEN 12 geldt weer hetzelfde, voor + de BASIC programmeurs niet echt spannend... + + +DE OPBOUW + + Zoals we al jaren van MSX gewend zijn moet alles zo moeilijk + en onhandig mogelijk zijn. Dus toen de 2+ standaard gemaakt + werd mocht het VRAM natuurlijk vooral niet groter worden, + nee!! Want dat zou handig zijn. Ook een snellere VDP was na- + tuurlijk uit den boze, kom nou! Maar men wilde natuurlijk + wel meer dan 256 kleurtjes. En dan moet je dus gaan rommelen + zoals ze bij ASCII gedaan hebben. + Om toch meer kleurtjes in dezelfde hoeveelheid VRAM te + proppen werd er dus besloten om van elke 4 pixels een aantal + bits (12) gemeenschappelijk te gebruiken. Op deze manier kon + er voor elke 4 pixels een basiskleur worden ingesteld. + Vervolgens kon voor elke pixel afzonderlijk een helderheid + worden ingesteld. Hoe dit werkt zie je in het volgende + schemaatje. + + + BIT7 BIT6 BIT5 BIT4 BIT3 BIT2 BIT1 BIT0 + PIXEL0 HE HE HE HE HE GR GR GR + PIXEL1 HE HE HE HE HE BL GR GR SCREEN 12 + PIXEL2 HE HE HE HE HE RO RO RO + PIXEL3 HE HE HE HE HE BL RO RO + + BIT7 BIT6 BIT5 BIT4 BIT3 BIT2 BIT1 BIT0 + PIXEL0 HE HE HE HE PA GR GR GR + PIXEL1 HE HE HE HE PA BL GR GR SCREEN 11 + PIXEL2 HE HE HE HE PA RO RO RO + PIXEL3 HE HE HE HE PA BL RO RO + + HE:Helderheid RO:Rood GR:Groen BL:Blauw PA:Palet + + + Zoals verwacht heeft SCREEN 12 een andere opbouw dan scherm + modus 11. Alle bits voor Rood Groen en Blauw worden voor de + betreffende pixels gebruikt als basiskleur. Vervolgens kan + er met de 5 HE-bits de helderheid per pixel worden ingesteld + zonder dat dit van invloed is op de andere 3 pixels. + Bij SCREEN 11 echter, zijn er maar 4 Helderheids bits per + pixel beschikbaar. En hierin schuilt dus de grap waar BASIC + gebruik van maakt in screen 10. Het derde bitje, waar PA + staat, is namelijk een switch die van PAlet verwisseld. + Er wordt hier namelijk gekozen tussen het standaard palet + zoals we dat in SCREEN 5 kennen, en het palet dat SCREEN 11 + zelf gebruikt. Is het bit laag, dan wordt de kleur-methode + van SCREEN 11 gehanteerd, en de SCREEN 5-palet mode. Waarom + ASCII speciaal hiervoor in BASIC een tiende scherm heeft + gemaakt weet ik niet, volgens mij hadden ze dit net zo goed + in SCREEN 11 kunnen doen, maar ja, van jongens die niet eens + kunnen tellen moet je natuurlijk niet te veel verwachten. + + + Verder valt er eigenlijk weinig te zeggen over deze screens. + Je weet nu waar wat staat, pas op met COPY's, hou de coordi- + naten wel in een viervoud. En dat is eigenlijk wel zo'n + beetje wat er te vertellen is. + + Ter illustratie van het geheel heb ik nog even een klein MC + programmaatje geschreven voor de V9958. Als het goed is staat + SCREEN12.BIN wel op de disk. Dit programmaatje zet de eerste + 65536 kleuren van SCREEN 12 op het scherm waarna je met cur- + sor up & down nog door het geheel heen kan scrollen, anders + mis je de laatste 44 lijnen. Het programmaatje zet 32 tinten + rood, gemengd met 32 tinten groen en 2 tinten blauw op het + scherm in de 32 aanwezige helderheden. Dit geeft: + 32x32x2x32=65536 van de 32x32x4x32=131072 aanwezige kleuren + als we er tenminste van uit gaan dat ik geen fouten heb ge- + maakt, wat opzich vrij onlogisch zou zijn. Een snelheids + wonder is het niet, in R800 mode kost het zo'n seconde of 3 + om de kleurtjes op het scherm te plaatsen en in Z80 mode een + seconde of zes. Daarna mag je er lekker op los scrollen met + 60 pixels per seconde... Oh joy!! + +Geluk d'r mee... + +Keizer + diff --git a/future_disk/24/v9958_in_ml.md b/future_disk/24/v9958_in_ml.md new file mode 100644 index 0000000..05c65df --- /dev/null +++ b/future_disk/24/v9958_in_ml.md @@ -0,0 +1,79 @@ + Ons liever Tobias heeft zich flink uitgesloofd, dus alweer een tekst van deze plezante zeer aardige en lieve jongen uit Nijverdal, bellen meiden, hij is nog vrij! + +V9958 in ML + + ���� + ���� + ���� + ���� + + + Ook dit heeft geloof ik al een keer eerder op de FD gestaan, + maar omdat ik weer over SCREEN 12 in basic begon toch nog een + keer de ML versie van SCREEN 12. + + Als eerste is het natuurlijk handig om te weten of de V9958 + wel aanwezig is. Ik persoonlijk kijk hier eigenlijk niet + eens naar. Als je zo dom bent om een 2+ programma op een + MSX 2 te runnen moet je natuurlijk niet vreemd opkijken als + het dan niet werkt. Maar soms kan het voorkomen dat je echt + ��n aparte routine voor de MSX2 en de MSX2+ hebt en dan is + het natuurlijk wel handig om te weten of de V9958 wel + aanwezig is. Dus eerst even een klein stukje assembly: + + CHKVDP: DI + LD A,$01 + OUT ($99),A + LD A,$8F + OUT ($99),A + PUSH AF + POP AF + IN A,($99) + LD D,A + XOR A + OUT ($99),A + LD A,$8F + OUT ($99),A + EI + JP_RTN: LD A,D + AND $3E + JP NZ,V_9938 + JP V_9958 + + Vervolgens is het misschien wel handig om SCREEN 12 aan te + zetten. Als je graag wilt mag je van mij SCREEN11 ook wel + aanzetten hoor! Okay, here we go: + + SCRN11: LD A,$08 + CALL $5F + DI + LD A,$18 + OUT ($99),A + LD A,$99 + OUT ($99),A + EI + + SCRN12: LD A,$08 + CALL $5F + DI + LD A,$08 + OUT ($99),A + LD A,$99 + OUT ($99),A + EI + + En dit zou toch echt moeten werken want mijn SCREEN12.BIN op + deze FD gebruikt dit stukje code ook. + + Dit is overigens ook handig voor het BASIC volk dat de MSX2+ + commando's i.v.m. compatibiliteit met de MSX2's met een + V9958 in stand wil houden. Gewoon intypen in WB, assembleren + en de .BIN file BLOADen aan het begin van je programmaatje. + + Hey guys, guess what?! It's 02.19 and I'm tired. Sleep well + and see you in the morning. I'm gonna have sweet dreams + about Amalia now.... + +Dikke zoen, + +Keizer... diff --git a/future_disk/25/clock_chip.md b/future_disk/25/clock_chip.md new file mode 100644 index 0000000..378c1dc --- /dev/null +++ b/future_disk/25/clock_chip.md @@ -0,0 +1,154 @@ + CURSUS CLOCK-KIJKEN, de clock-chip nader bekeken. + ================================================= + + ���� + ���� + ���� + ���� + + + Dat de clock-chip in de MSX gebruikt wordt om de tijd in bij + te houden, zullen de meeste mensen wel kunnen gokken, maar er + schuilt heel wat meer achter die "32 bytes S-RAM". + +DE TIJD + + De tijd, want dat is toch waarvoor men de klokchip meestal + zal gebruiken. In BASIC is dat niet zo'n probleem, een + simpele GET TIME helpt de BASIC-er wel aan de juiste tijd, ter- + wijl onder een DOS omgeving een BDOS call naar $002C ook het + probleem wel uit de wereld helpt. In een BASIC omgeving + wellicht makkelijk, maar in machinetaal wordt het echter al + een stuk moeilijker, tenzij men natuurlijk naar dezelfde BDOS + call grijpt, maar hoe zit het eigenlijk met alle andere infor- + matie in de clock-chip?? + +DE OPBOUW + + De opbouw van de clock-chip doet ietwat vreemd aan, in de + eerste plaats staat de data al niet in echt S-RAM, en is het + geheel niet opgedeeld in bytes, hetgeen de aanhalingstekentjes + in de inleiding verklaart. Eigenlijk is de clock-chip verdeeld + in 4 blokken van 16 vierbits registers. Nybble werk dus, YUK!! + + Gelukkig voorziet het BIOS in een routine om de clock-chip uit + te lezen, hetgeen de minder ervaren programmeurs weer een paar + uur scheelt. Dus, 64 nybbles om alle data in op te slaan, maar + waar staat dan wat? Dat was het eerste probleem waar ik op + stuitte bij mijn speurtocht door de clock-chip. Over de eerste + twee blokken, die voor de tijd & datum gebruikt worden, was + nog wel informatie te vinden. Over de laatste twee blokken + echter, was niets te vinden. Nu is het ongetwijfeld zo dat wel + in een of ander technical-databook deze informatie staat, maar + via 'normale' wegen, bleek het niet makkelijk om deze informa- + tie te achterhalen. Mij is dit dan ook alleen gelukt via het + befaamde "trial & error" proces, waarbij de nadruk toch wel op + error lag... + +NYBBLE WERK... + + Vierenzestig nybbles dus, die via de de BIOS routine $01F5 uit + de SUB-ROM te lezen zijn. De nybbles waarin de data staat bom- + barderen we maar even tot registers, en dan zijn er dus nog de + vier blokken die te selecteren zijn. De eerste twee blokken wa- + ren dus voor de tijd en datum, de overige twee voor de instel- + lingen van BASIC. Als invoer heeft de BIOS routine in register + C "twee variabelen" nodig. In bit 4 & 5 van register C staat + welk blok we wensen te lezen, 0-3 dus. In bit 0-3 staat dus + het registernummer 0-15. Als output komt de routine met in reg + A het gelezen nybble. De laaste 4 bits dienen genegeerd te + worden. Maak deze dus maar voor het gemak 0. En dan nu dus de + tabel, die ik zoals gezegd heb moeten uitvogelen door domweg + wat te proberen. Van 3 reg's ben ik niet te weten gekomen wat + hun functie is, en de laatste 3 registers zijn voor intern ge- + bruik waar men dus niets aan heeft. Het enige dat ik er van + weet is dat het respectievelijk de MODE, TEST en RESET regis- + ters zouden moeten zijn, hun functie is mij onduidelijk. + + + REG �V block 0 �V BLOCK 1 �V BLOCK 2 �V BLOCK 3 �V + �W�W�W�W�W�W�W�W�U�W�W�W�W�W�W�W�W�W�W�W�W�U�W�W�W�W�W�W�W�W�W�W�W�W�U�W�W�W�W�W�W�W�W�W�W�W�W�U�W�W�W�W�W�W�W�W�W�W�W�W�S + $00 �V SEC 2 �V ONGEBRUIKT �V -ONBEKEND- �V STRING I.D �V + $01 �V SEC 1 �V ONGEBRUIKT �V ADJUST X �V CHR0 LN �V + $02 �V MIN 2 �V MIN 2 (AL) �V ADJUST Y �V CHR0 HN �V + $03 �V MIN 1 �V MIN 1 (AL) �V -ONBEKEND- �V CHR1 LN �V + $04 �V UUR 2 �V UUR 2 (AL) �V WIDTH LN �V CHR1 HN �V + $05 �V UUR 1 �V UUR 1 (AL) �V WIDTH HN �V CHR2 LN �V + $06 �V DAG V WEEK �V DAG V WEEK �V VOOR KLEUR �V CHR2 HN �V + $07 �V DAG 2 �V DAG 2 (AL) �V ACHT KLEUR �V CHR3 LN �V + $08 �V DAG 1 �V DAG 1 (AL) �V RAND KLEUR �V CHR3 HN �V + $09 �V MAAND 2 �V ONGEBRUIKT �V SCREEN SET �V CHR4 LN �V + $0A �V MAAND 1 �V 12/24 UURS �V "BEEP"INFO �V CHR4 HN �V + $0B �V JAAR 2 �V SCHRIKKELJ �V LOGO KLEUR �V CHR5 LN �V + $0C �V JAAR 1 �V ONGEBRUIKT �V -ONBEKEND- �V CHR5 HN �V + $0D �V MODE------ �V MODE------ �V MODE------ �V MODE------ �V + $0E �V TEST------ �V TEST------ �V TEST------ �V TEST------ �V + $0F �V RESET----- �V RESET----- �V RESET----- �V RESET----- �V + �W�W�W�W�W�W�W�W�U�W�W�W�W�W�W�W�W�W�W�W�W�U�W�W�W�W�W�W�W�W�W�W�W�W�U�W�W�W�W�W�W�W�W�W�W�W�W�U�W�W�W�W�W�W�W�W�W�W�W�W�S + + + Ervaren ML-programmeurs kunnen hiermee uit de voeten, voor + het geval dat er echter nog het een en ander onduidelijk is + zal ik alles even apart behandelen. + + +NOG EENS DE TIJD + + Zoals in de tabel te zien is komen sommige variabelen voor + met een 1 en een 2 erachter. Dit zijn dus Binairy Coded Deci- + mals. Voor diegenen die niet weten wat dit inhoud; Gewoon het + eerste getal, dat het tweede cijfer voorstelt, met 10 verme- + nigvuldigen en de andere nybble erbij optellen. Overal waar + LN en HN staat bedoel ik HighNybble en LowNybble, wat dat in- + houd behoeft naar ik aanneem geen uitleg. Van de registers + waar -ONBEKEND- staat heb ik simpelweg de functie niet van + kunnen achterhalen.Mocht iemand wel weten waar deze registers + (paren) voor dienen, of mocht iemand andere onvolkomendheden + in de tabel ontdekken, dan wordt het zeer op prijs gesteld + als die persoon ons hiervan op de hoogte stelt. -Xela?- + (NvdR: en jij optimist meent dat daar iemand op reageert?) + +ANDERE OPSLAG METHODEN + + Een uitzondering is bijvoorbeeld al het jaartal, dit wordt ge + vormd door (JAAR2*10)+8 en de andere nybble. De offset voor + het jaar is dus eigenlijk 1980. + + Dag v week is simpelweg de dag van de week. + + 12/24Uurs geeft aan of de 12uurs klok of de 24uurs klok door + de gebruiker is ingesteld. + + Schrikkelj is een tellertje voor intern gebruik waar wordt + bijgehouden of we wel of niet met een schrikkeljaar te maken + hebben. Deze is overigens 2 bits lang. + + De ADJUST X & Y zijn de waarden die we in BASIC met het SET + ADJUST commando kunnen instellen. Hierbij gaat het om 2-compl + nybbles. + + De registers WIDTH tm RAND KLEUR spreken voor zich. + + Dan komt er een register dat volledig uit losse bits is opge- + bouwd. Bit0: Functie toesten (0:uit 1:aan ) + Bit1: Key Klick (0:uit 1:aan ) + Bit2: Type printer (0:MSX 1:IBM ) + Bit3: Standaard Baudrate (0:1200 1:2400) + Bij gebrek aan een betere naam noem ik dit maar "SCREEN SET". + + Dan het register met de BEEP informatie: Bit 0-1: Type BEEP + Bit 2-3: Volume /4 + + Vervolgens het register dat de kleur van het MSX-logo bij de + reset routine representeerd. + + Het register dat ik STRING-ID heb genoemd heeft betrekking op + de daarop volgende registers. STRING-ID bepaald de functie + van de daarop volgende STRING. De STRING kan namelijk PROMPT, + TITLE & PASSWORD zijn. Bij resp. 1,0 & 2 voor STRING-ID. + + De rest van de registers zijn dus gereserveerd voor de STRING + die door STRING-ID een functie had gekregen. + + En dan hebben we zo'n beetje alle registers gehad. Waarmee de + clock-chip dus ook zo'n beetje afgehandeld zou mo diff --git a/future_disk/25/mcode_special_4.md b/future_disk/25/mcode_special_4.md new file mode 100644 index 0000000..bbd51f4 --- /dev/null +++ b/future_disk/25/mcode_special_4.md @@ -0,0 +1,282 @@ + + MCODE SPECIAL (4) + + part 1 + + + We gaan verder met deze zeer special cursus... + + VEILIG (de routine die een vlag plaats/weghaald) + + Als je op SHIFT drukt moet de computer een vlag plaatsen, + stond er echter al een vlag wil je graag dat deze weggehaald + wordt. De snelheid van de machinetaal levert dit keer een + probleem op: als de speler 1 keer op SHIFT gedrukt denkt te + hebben is onze hoofdlus vaak meerdere keren (soms wel 4) door- + lopen, hetgeen tot gevolg heeft dat je de vlag aan en uit + ziet flikkeren i.p.v. netjes omwisselen. Je kunt dit voorkomen + m.b.v de volgende routine, die je moet plaatsen voordat + op de toets gereageerd wordt: + + LD A,(VORIGSHIFT) ; als de vorige keer shift al + AND A ; ingedrukt was, nu niet meer + RET NZ ; reageren (voorkomen van: aan/uit) + INC A ; wordt 1 (dus NotZero) + LD (VORIGSHIFT),A ; volgende keer niet reageren + + Als er nu op SHIFT gedrukt wordt, wordt dit opgeslagen in het + label VORIGSHIFT(er staat 1 in). + Zodra nu de volgende keer weer op SHIFT wordt gedrukt (door + te lang inhouden) wordt dit geblokkeerd door de RET NZ. + Als SHIFT losgelaten wordt moet VORIGESHIFT natuurlijk wel + weer op nul gezet worden, omdat je anders maar 1 vlag kan + plaatsen per spel. + + Als er op Shift gereageerd moet worden vindt eerst weer een + aanroep van de routine die eerder beschreven werd: + + CALL HAALBLOKNR ; in A komt bloknr. + + In A staat nu het bloknummer, dit is dus de plaats in het + dataveld waarop gedrukt werd en waarop de speler een vlag wil + plaatsen. Net als in de routine GEDRUKT wordt eerst weer geke- + ken of je op deze plaats wel een vlag mag plaatsen: + + LD HL,DATA + LD C,A + LD B,0 ; nu in HL het DATA-blokje, + ADD HL,BC ; waarop je stond. + BIT 6,(HL) ; al zichtbaar ? + RET NZ ; ja: geen vlag + + Dan wordt onderzocht of er een vlag geplaatst moet worden of + weggehaald moet worden: + + BIT 5,(HL) ; was het al een vlag ? + JR Z,NUVLAG ; we plaatsen een vlag + RES 5,(HL) ; weg met de vlag + LD A,144 ; Source Xco van Onzichtbaar blokje + LD (SX),A + LD HL,BLOKDATA ; laat ook zien. + JP COPY ; einde VEILIG + + Als de vlag weggehaald moets worden wordt er een onzichtbaar + blokje overheen geplaatst en in het dataveld aangegeven dat + de vlag weg is. Moest de vlag geplaatst worden volgt de + volgende routine: + +NUVLAG: + SET 5,(HL) ; Zet DATAblokje op vlag. + LD A,160 ; Source Xco van vlag + LD (SX),A ; DX en DY al in HAALBLOKNR + gezet + LD HL,BLOKDATA ; laat ook een vlag zien. + JP COPY ; einde VEILIG + + +TESTEIND (testen of je gewonnen bent) + + Testen of alles zichtbaar is wat zichtbaar moet zijn, komt er + op neer door te kijken of het aantal zichtbare blokjes (dat we + in GEDRUKT geteld hebben) + het aantal mijnen (dat vast ligt) = + het aantal blokjes op het scherm (16*13). De volgende routine + doet dat: + +TESTEIND: LD A,(AANTALMIJNEN) ; als alle blokjes die + geen mijn zijn + LD B,A + LD A,(AANTALZICHTBAAR) ; zichtbaar zijn + ADD A,B + CP MAXBLOKJES ; heb je gewonnen. + RET NZ + LD A,1 + LD (EINDBT),A + jp #c0 + RET + + Merk op dat er, omdat deze routine in de hoofdlus (altijd) + wordt aangeroepen, nu een onafgebroken rij BEEP's klinken als + je gewonnen hebt. + Als je wilt kun je in de hoofdlus een test op EINDBT toevoegen, + die springt naar een soort van einddemo, maar ik vind dit niet + interessant genoeg om zoiets te gaan programmeren (lees: ik + ben hier te lui voor) (aangezien ene K.Dols er toch niet aan + begint deze tekst te lezen verwacht ik hier geen N.V.D.R ..... + of toch??.....)(NvdR: Gaap gaap). + + Zo, het spel is nu in principe klaar en kan al gespeeld wor- + den, maar we willen nog graag dat het drukken op een leeg + hokje een soort kettingreactie van zichtbaar maken tot gevolg + heeft. Hoe kun je nu zoiets bereiken ? + Als een leeg hokje zichtbaar wordt gemaakt, wordt naar de + routine CLEARDATA gesprongen. + In deze routine wordt linksboven op het scherm begonnen met + kijken of er een leeg hokje staat (in praktijk wordt in het + DATAveld gekeken). + Zolang als er geen leeg hokje wordt gevonden wordt er 16 bij + de xco opgeteld tot het einde van de regel bereikt wordt. + Dan wordt er 16 bij de yco opgeteld en weer begonnen op + xco=0 ect. tot het einde van het scherm (en DATAveld) bereikt + is. + Als er wel een leeg hokje gevonden wordt, wordt er doorge- + sprongen naar de routine DOCLEAR. + In DOCLEAR gebeurt het eigenlijke zichtbaar-maak-werk. Als er + een hokje zichtbaar gemaakt wordt, wordt de teller FOUND + verhoogd. De routine wordt dan nogmaals herhaald (dus het hele + scherm wordt opnieuw onderzocht naar e.v. (nieuwe, maar ook + oude) lege hokjes: dit is dus de kettingreactie. + Als er tenslotte geen nieuwe hokjes zichtbaar gemaakt worden, + wordt de routine VULSCHERM aangeroepen, die het hele scherm + opnieuw vult met blokjes. + + Dat regelt de volgende routine: + + Welke routine? Zie voor deze routine tekst (2)! + + MCODE SPECIAL (4) + + part 2 + + + En we gaan verder met die routine: + + CLEARDATA: + CALL MAAKZICHTBAAR ; maak het lege hokje + ; zichtbaar + CLEARREPEAT: ; naar dit label wordt teruggesprongen als er + ; hokjes zichtbaar gemaakt zijn: deze kunnen leeg + ; zijn => herhaal + LD B,MAXBLOKJES + LD HL,DATA + XOR A ; begin linksboven + LD (XCO1),A ; om alle coordinaten te door- + ; lopen en te kijken welke + LD (YCO1),A ; blokjes rondom staan + CLEARDATALOOP: + PUSH HL + PUSH BC + LD A,(HL) + CP ZICHTBAARLEEG ; =&B01000000 + CALL Z,DOCLEAR + POP BC + POP HL + INC HL + LD A,(XCO1) ; verhoog xco tot einde + ADD A,16 ; beeldscherm steeds met 16 => + ; volgend blokje + CALL Z,YHOGER ; als xco=256 dan is xco 0: + ; verhoog yco + LD (XCO1),A + DJNZ CLEARDATALOOP + + + LD A,(FOUND) ; is er een blokje zichtbaar + AND A ; gemaakt + JP Z,VULSCHERM ; nee, sluit af met opbouw + ; van hele scherm. + XOR A ; begin opnieuw : nog niks zichtbaar + ; gemaakt + LD (FOUND),A + JP CLEARREPEAT ; en herhalen tot alles + ; zichtbaar is + + YHOGER: LD A,(YCO1) + ADD A,16 + LD (YCO1),A + XOR A ; xco op 0 + RET + + Als we in DOCLEAR aankomen weten we zeker dat in XCO1 en YCO1 + de coordinaten staan van het lege blokje. Rondom deze coordinaten + moeten we dus gaan kijken. Als het blokje geen rand-blokje is + zijn er 8 plaatsen rondom. In HL staat het adres in het DATA + veld waar het lege blokje zich bevindt. + Er moet dan gekeken worden op de volgende adressen: + + HL-17: linksboven het lege blokje + HL-16: recht er boven + HL-15: rechtsboven + HL-1: links + HL+1: rechts + HL+15: linksonder + HL+16: recht er onder + HL+17: rechtsonder + + Als het blokje zich bevindt aan ��n van de randen (of in de + hoeken) moeten er minder geheugenadressen in het DATAveld + onderzocht worden. We kunnen de volgende data aanmaken: + + + ;---- Rondtedata's: Geven aan hoeveelbyte verder/terug de + ; blokjes staan, die rondom een leeg hokje zitten. + ; Eerste byte is aantal blokjes = aantal bytes in die + ; rondtedata. + + DATAMIDDEN: DB 8,-17,-16,-15,-1,1,15,16,17 + DATALINKS: DB 5,-16,-15,1,16,17 + DATARECHTS: DB 5,-17,-16,-1,15,16 + DATABOVEN: DB 5,-1,1,15,16,17 + DATAONDER: DB 5,-17,-16,-15,-1,1 + DATALB: DB 3,1,16,17 + DATARB: DB 3,-1,15,16 + DATALO: DB 3,-16,-15,1 + DATARO: DB 3,-17,-16,-1 + + Om te weten welke Rondtedata gebruikt moet worden, moeten we + eerst weten waar het blokje zich op het scherm bevindt: + n.l. aan ��n van de randen of in ��n van de hoeken of ergens + in het midden. + + Dit wordt onderzocht in de routine ZOEKRONDTEDATA. + + ZOEKRONDTEDATA: + LD A,(XCO1) + CP 16 + JR NC,NIETLINKS + LINKS1: LD A,(YCO1) + CP 16 + JR NC,NIETBOVEN1 + LINKSBOVEN: LD DE,DATALB + RET + NIETLINKS: CP 15*16 + JP C,NIETRECHTS + RECHTS1: LD A,(YCO1) + CP 16 + JR NC,NIETBOVEN2 + RECHTSBOVEN: LD DE,DATARB + RET + NIETBOVEN1: CP MAXBLOKJES-16 ; onderrand dataveld + ; (laatste regel) + JR C,LINKSMID + LINKSONDER: LD DE,DATALO + RET + LINKSMID: LD DE,DATALINKS + RET + NIETRECHTS: LD A,(YCO1) + CP 16 + JR NC,NIETBOVEN + BOVEN1: LD DE,DATABOVEN + RET + NIETBOVEN: CP MAXBLOKJES-16 ; idem + JR C,MIDDEN + ONDER1: LD DE,DATAONDER + RET + MIDDEN: LD DE,DATAMIDDEN + RET + NIETBOVEN2: CP MAXBLOKJES-16 ; idem + JR NC,RECHTSONDER + RECHTSMID: LD DE,DATARECHTS + RET + RECHTSONDER: LD DE,DATARO + RET + + Deze routine is niet bijster interessant en ook niet zo leuk + om te schrijven, maar ze werkt en heeft tot resultaat dat er + in DE, de juiste Rondtedata komt te staan. + + Maar dan...plotseling een eind aan deze tekst: + + Op de volgende FD het allerlaatste deel van deze zeer interes- + sante cursus! + +Ruud Gelissen diff --git a/future_disk/25/msx-dos2_deel_1.md b/future_disk/25/msx-dos2_deel_1.md new file mode 100644 index 0000000..1d5396b --- /dev/null +++ b/future_disk/25/msx-dos2_deel_1.md @@ -0,0 +1,193 @@ + MSX-DOS2, deel 1 + + ���� + ���� + ���� + ���� + + +Waar moet dat heen met de FD?! + + Kreeg ik toch laatst zomaar een brief van een lezer, HELP!?! + Hoe kan dit?!? Wat moet dat! Kom nou, FD-leden schrijven geen + brieven!! Nou ja, uit deze aangename verrassing blijkt dat er + toch nog FD leden zijn die zo nu en dan eens een keertje een + briefje durven te schrijven. Om deze pen-vriend te beschermen + zal ik zijn identiteit niet prijsgeven. Neen, deze held mag + anoniem blijven. + +MSX-DOS 2 + + Want daar ging de brief namelijk over, hoe onze vriend met MSX + DOS 2 kon werken in assembly, de calls dus... En als de FD een + brief over een onderwerp ontvangt, dan moet dat wel iets HEEL + belangrijks zijn. Vandaar dat ik naast de brief die onze held + inmiddels heeft ontvangen, ook nog een stukje op de FD aan die + onzin wil wijden. Ik meende zelf dat DOS2 eigenlijk een open + boek was, maar blijkbaar zijn er toch nog mensen die hier nog + wel 't een en ander over willen weten. Daar gaan we dus... + + +DOS2 in BASIC + + Ik weet niet hoe het bij de andere MSX-en zit, maar bij de MSX + Turbo-R [DOS2.30] is het zo dat de BASIC programmeur nog een + aantal extra commando's tot zijn beschikking heeft. Door + gebrek aan documentatie ken ik deze niet allemaal, maar een + aantal ken ik er toevalling uit m'n hoofd. Okay... + + CALL RAMDISK (xx) > Maak een ramdisk van [xx] kB aan. + + CALL CHDRV ("x:") > Maak van [x] de default drive. + + CALL CHDIR ("xx") > Ga naar directory [xx] (zoals DOS) + Hierbij behoren "\" & ".." ook tot + de mogelijkheden. + + CALL MKDIR ("xx") > Maak directory aan, als CHDIR. + + CALL RMDIR ("xx") > Verwijder directory, als CHDIR. + + Het zal best dat er nog meer commando's mogelijk zijn, maar ik + ken ze niet. Mocht iemand wel meer informatie hebben dan wordt + een belletje altijd gewaardeerd. Tot zover BASIC, nu naar het + echte werk, DOS2 in ML. + + +MSX-DOS2 in Assembly langue. + + Ik wil hier verder niet al te diep op ingaan, simpelweg een + beschrijving van de DOS2 calls, gewijzigde registers en input + & output registers. That's it! Hou er dus rekening mee dat + alle registers gewijzigd worden als ze al niet als output re- + gister dienen. Eerst de zooi PUSHen dus. DOS1 voor de call + betekent dat de routine DOS1 compatible is, anders dus NIET. + Here it goes... + + Kort overzicht: + + $00 [DOS1] Bye Bye! + $01 [DOS1] Console in + $02 [DOS1] Console out + $03 [DOS1] Aux in + $04 [DOS1] Aux out + $05 [DOS1] Printer out + $06 [DOS1] Direct console I/O + $07 [DOS1] Direct console in + $08 [DOS1] Console in without echo + $09 [DOS1] String out + $0A [DOS1] Buffered line in + $0B [DOS1] Console status + $0C [DOS1] DOS version + $0D [DOS1] Disk reset + $0E [DOS1] Select disk + $0F [DOS1] Open file FCB + $10 [DOS1] Close file FCB + $11 [DOS1] Search first FCB + $12 [DOS1] Search next FCB + $13 [DOS1] Delete file FCB + $14 [DOS1] Sequential read FCB + $15 [DOS1] Sequential write FCB + $16 [DOS1] Create file FCB + $17 [DOS1] Rename file FCB + $18 [DOS1] Get login vector + $19 [DOS1] Get current drive + $1A [DOS1] Set Disk transfer address + $1B [DOS1] Get allocation info + $1C [----] N.U. + $1D [----] N.U. + $1E [----] N.U. + $1F [----] N.U. + $20 [----] N.U. + $21 [DOS1] Random read FCB + $22 [DOS1] Random write FCB + $23 [DOS1] Get file size FCB + $24 [DOS1] Set random record FCB + $25 [----] N.U. + $26 [DOS1] Random block write FCB + $27 [DOS1] Random block read FCB + $28 [DOS1] Random zero fill FCB + $29 [----] N.U. + $2A [DOS1] Get date (Though I prefer to use Roses) + $2B [DOS1] Set date Hmmm, almost funny �W�W�W�W�[ + $2C [DOS1] Get time + $2D [DOS1] Set time + $2E [DOS1] -re-set verify flag + $2F [DOS1] Sector read + $30 [DOS1] Sector write + + $31 [DOS2] Get disk parameters + $32 [----] N.U. + $33 [----] N.U. + $34 [----] N.U. + $35 [----] N.U. + $36 [----] N.U. + $37 [----] N.U. + $38 [----] N.U. + $39 [----] N.U. + $3A [----] N.U. + $3B [----] N.U. + $3C [----] N.U. + $3D [----] N.U. + $3E [----] N.U. + $3F [----] N.U. + $40 [DOS2] Find first entry + $41 [DOS2] Find next entry + $42 [DOS2] Find new entry + $43 [DOS2] Open file handle + $44 [DOS2] Create file handle + $45 [DOS2] Close file handle + $46 [DOS2] Ensure file handle + $47 [DOS2] Dupe file handle + $48 [DOS2] Read from file handle + $49 [DOS2] Write to file handle + $4A [DOS2] Move file handle pointer + $4B [DOS2] Device I/O control + $4C [DOS2] Test file handle + $4D [DOS2] Delete file/dir + $4E [DOS2] Rename file/dir + $4F [DOS2] Move file/dir + $50 [DOS2] Set/Get file attributes + $51 [DOS2] Set/Get file time//date + $52 [DOS2] Delete file handle + $53 [DOS2] Rename file handle + $54 [DOS2] Move file handle + $55 [DOS2] Set/Get file handle attributes + $56 [DOS2] Set/Get file handle date//time + $57 [DOS2] Get disk transfer address + $58 [DOS2] Get verify flag + $59 [DOS2] Get current dir + $5A [DOS2] Change dir + $5B [DOS2] Parse pathname + $5C [DOS2] Parse filename + $5D [DOS2] Check character + $5E [DOS2] Get whole path string + $5F [DOS2] Flush disk buffers + $60 [DOS2] Fork a child process + $FD [DOS6] Spoon an adult process + $61 [DOS2] Rejoin parent process <- T'is net spoorloos + $62 [DOS2] Terminate with error code + $63 [DOS2] Define abort exit routine + $64 [DOS2] Define disk error handler routine + $65 [DOS2] Get previous error code + $66 [DOS2] Explain error code + $67 [DOS2] Format a disk + $68 [DOS2] Ramdisk settings + $69 [DOS2] Allocate sector buffers + $6A [DOS2] Logical drive assignment + $6B [DOS2] Get environment item + $6C [DOS2] Set environment item + $6D [DOS2] Find environment item + $6E [DOS2] Set/Get disk check status + $6F [DOS2] Get DOS version + $70 [DOS2] Set/Get redirection status + + + Hoppa, da's een hele lijst. Maar dan wel een lijst waar je + niets aan hebt. Voor de calls moet je uiteraard ook de + specifieke gegevens hebben. En laat ik nou net zo aardig zijn + om die je niet te geven... Sorry, geen tijd meer. Volgende FD! + + +Tobias "Gna, gna, gna" Keizer + diff --git a/future_disk/27/mcode_special_5.md b/future_disk/27/mcode_special_5.md new file mode 100644 index 0000000..d324b33 --- /dev/null +++ b/future_disk/27/mcode_special_5.md @@ -0,0 +1,119 @@ + Ruud bespreekt het laatste stukje uit zijn Minesweeper source... + + MCODE CURSUS (5) + + + We gaan weer verder... + + We weten nu hoeveel adressen onderzocht moeten worden en welke + adressen dat zijn (we weten n.l. hun Offset t.o.v. het adres + van het lege blokje). In HL staat nog steeds het adres van het + lege blokje. Het onderzoeken van de adressen van de blokjes + eromheen gebeurt nu met de volgende routine: + + DOCLEAR: + LD A,(DE) ; aantal plaatsen rondom + LD B,A ; die ev. nog zichtbaar moeten worden + DOCLEARLOOP: PUSH HL + PUSH BC + INC DE + LD B,0 + LD A,(DE) ; offset (in geheugenplaatsen) + BIT 7,A + CALL NZ,NEGATIEF + LD C,A ; t.o.v. het lege blokje + ADD HL,BC ; optellen bij adres lege blokje + BIT 6,(HL) + CALL Z,ZICHTBAAR ; blokje was onzichtbaar + ; wordt nu zichtbaar + POP BC + POP HL + DJNZ DOCLEARLOOP + RET + ZICHTBAAR: LD A,(FOUND) + INC A + LD (FOUND),A + JP MAAKZICHTBAAR + NEGATIEF: DEC B ; 255 + RET + + Om bij HL een 8 bits getal op te tellen moet je dit 8 bits + getal in BC zetten (DE kan ook). B moet 0 gemaakt worden en in + C moet het 8 bits getal gezet worden. + + Door GEN80 wordt -1 vertaald in 256-1=255 + -16 wordt dus 256-16=240 + + Bij 8 bits getallen was het zo dat optellen met 255 hetzelfde + betekende als er 1 van aftrekken, maar bij 16 bits getallen + wordt er gewoon 255 bij opgeteld. + Als B echter op 255 staat werkt de truuk wel weer. + Hiervoor zorgt de subroutine NEGATIEF. + + Zoals je kunt zien maak ik weer gebruik van de routine + MAAKZICHTBAAR, die ik voor de overzichtelijkheid hieronder + nog maar even herhaal: + + MAAKZICHTBAAR: + SET 6,(HL) ; in DATA aangeven dat + ; dit blokje al + LD HL,AANTALZICHTBAAR; zichtbaar is + INC (HL) + RET + + Merk verder nog op dat HL telkens bewaard moet worden ( op de STACK ), omdat + uitgegaan wordt van Offset's t.o.v. het adres van het lege blokje. + + Verder wil ik nog even kwijt dat de routine CLEARDATA vast wel + op de een of andere manier sneller kan gemaakt worden.(b.v. + door gebruik van de overgebleven bit in de DATA, om aan te + geven of een leeg blokje als eens onderzocht is) + Maar persoonlijk vond ik dat niet nodig, aangezien ik het dan + alleen maar moeilijker zou maken dan het eigenlijk is. + + + Zo, tot zover de bespreking van de routines van het spel + Minesweeper. + + De listing staat in zijn geheel nog een keer op de Future- + Disk als ASCII-tekst in MINESW.GEN. + Wil je de routine in WBASS2 gebruiken, moet je wel eerst de + header weghalen. Dus deze routine moet eruit: + + DB #FE ; om de file in BASIC + DW ST ; m.b.v. BLOAD in te kunnen laden + DW EN ; weglaten bij gebruik van WBASS2 + DW ST + + Ik wens je erg veel plezier met deze routines en daag je uit + de volgende uitbreidingen eens te programmeren: + + - Een routine, die zelf random velden opbouwt. + Op zich is dit niet zo moeilijk als je misschien denkt. + Als buffer voor randomgetallen gebruik je een geschikt + deel van het geheugen b.v. de basicrom, waarin je met + LD A,R een adres kiest. + Staat op een adres een b.v. waarde >196 zet je een mijn + neer, anders niet. M.b.v. de al geschreven routine voor + het random wissen moet je nu vrij eenvoudig een routine + kunnen schrijven die rondom de juiste getallen plaatst. + Aangezien deze routine wezenlijk is voor het spel zal ik + misschien op een van de volgende FutureDisks de routine + publiceren. + - fatsoenlijke routine, die aangeeft dat je gewonnen bent + i.p.v wat nutteloze Beeps, die alleen een programmeur + interessant vind (om te testen). + - Als je afgaat wordt het hele veld zichtbaar gemaakt, maar + alle vlaggen blijven staan zodat je niet kunt zien of + hieronder echt een mijn zat. + Los dit b.v. op door een routine te schrijven die alle 5e + bit's in het dataveld 0 maakt (de vlaggen weghaalt), voor- + dat VULSCHERM wordt aangeroepen. + - Hetzelfde spel omzetten naar Screen 7, een klokje toevoe- + gen, puntentelling bijhouden en de snelste tijd laten zien. + - Blokjes 8x8 formaat geven (en dus meer blokjes op het + scherm zetten). + + SUCCES !! + +Ruud Gelissen diff --git a/Future Disk/27/Rotatie.md b/future_disk/27/rotatie.md similarity index 100% rename from Future Disk/27/Rotatie.md rename to future_disk/27/rotatie.md diff --git a/future_disk/28/msx-dos2_deel_2.md b/future_disk/28/msx-dos2_deel_2.md new file mode 100644 index 0000000..b880473 --- /dev/null +++ b/future_disk/28/msx-dos2_deel_2.md @@ -0,0 +1,94 @@ + De DOS2 cursus gaat weer verder... + + ASCII'S WAY TO TORMENT MANKIND + + ���� + ���� + ���� + ���� + + + + Oftewel, het is weer tijd voor DOS2. Niet zoveel deze keer, + want echt veel tijd heb ik niet. Voor deze keer maar een paar + functies specifiek onder de loep, we komen vanzelf een keer + aan bij $70. Overigens ga ik inderdaad niet de DOS1 calls + behandelen. Deze info heeft wel vaker ergens anders gestaan. + Mocht er nu echt iemand zijn die daar toch intresse in heeft, + dan is een belletje naar de redactie genoeg om dat probleem + op te lossen. + + + GET DISK PARAMETERS [_DPARM] + + IN: C = $31 + DE = Pointer to 32byte buffer + L = Drive number + RES: A = Error code + DE = Preserved + + Created block: +$00 Physical drive number + +$01 Sector size ($01FF) + +$03 Sector per cluster + +$04 Number of reserved sectors + +$06 Number of FATs + +$07 Entries in root directory + +$09 Number of logical sectors + +$0B Media descriptor byte + +$0C Sectors per FAT + +$0D First root directory sector + +$0F First data sector + +$11 Maximum cluster number + +$13 Dirty disk flag + +$14 Volume ID + +$18 1F Unused + + + + FIND FIRST ENTRY [_FFIRST] + + IN: C = $40 + DE = File info block / ASCIIZ string pointer + HL = ASCIIZ filename pointer (If DE = FIB) + B = Attributes + IX = New file info block + RES: A = Error code + IX = Matching entry + + + + FIND NEXT ENTRY [_FNEXT] + + IN: C = $41 + IX = Pointer to file info block from _FFIRST + RES: A = Error code + IX = Matching next entry + + + FIND NEW ENTRY [_FNEW] + + IN: C = $42 + DE = File info block / ASCIIZ string pointer + HL = ASCIIZ filename pointer (If DE = FIB) + B = Attributes + IX = New file info block + RES: A = Error code + IX = New entry + + + + OPEN FILE HANDLE [_OPEN] + + IN: C = $43 + DE = Drive/path/file ASCIIZ of FIB + A = Mode: b0, no write b1, no read b2 inheritable + RES: A = Error code + B = New file handle + + + En dat was 't alweer. Sorry, ik weet 't, het is niet veel, + maar om eerlijk te zijn heb ik ook wel wat beters te doen. + Zoals slapen, want het is al weer gruwelijk laat... Tot FD 29 + maar weer, met hopelijk iets meer dan deze aflevering... + +Tobias Keizer diff --git a/future_disk/28/msx-dos2_deel_3.md b/future_disk/28/msx-dos2_deel_3.md new file mode 100644 index 0000000..7745a8d --- /dev/null +++ b/future_disk/28/msx-dos2_deel_3.md @@ -0,0 +1,96 @@ + THE DOS2 COURSE GOES ON AND ON AND... + ASCII'S WAY TO TORMENT MANKIND + + ���� + ���� + ���� + ���� + + + + In other words, it time for DOS2 again. Not too much this time + as time is indeed something I do not have... Just a few func- + tions a little more specified, we'll reach $70 eventually, + some day... Right?!? Ah well, we'll see... By the way, I'm + not going to go into all that DOS1 BDOS crap, just the speci- + fic DOS2 calls... DOS1 info can be found practically every- + where, but if someone really wants that info, a call -as in + phonecall, letter - will suffice to solve that problem. + + + + GET DISK PARAMETERS [_DPARM] + + IN: C = $31 + DE = Pointer to 32byte buffer + L = Drive number + RES: A = Error code + DE = Preserved + + Created block: +$00 Physical drive number + +$01 Sector size ($01FF) + +$03 Sector per cluster + +$04 Number of reserved sectors + +$06 Number of FATs + +$07 Entries in root directory + +$09 Number of logical sectors + +$0B Media descriptor byte + +$0C Sectors per FAT + +$0D First root directory sector + +$0F First data sector + +$11 Maximum cluster number + +$13 Dirty disk flag + +$14 Volume ID + +$18 1F Unused + + + + FIND FIRST ENTRY [_FFIRST] + + IN: C = $40 + DE = File info block / ASCIIZ string pointer + HL = ASCIIZ filename pointer (If DE = FIB) + B = Attributes + IX = New file info block + RES: A = Error code + IX = Matching entry + + + + FIND NEXT ENTRY [_FNEXT] + + IN: C = $41 + IX = Pointer to file info block from _FFIRST + RES: A = Error code + IX = Matching next entry + + + + FIND NEW ENTRY [_FNEW] + + IN: C = $42 + DE = File info block / ASCIIZ string pointer + HL = ASCIIZ filename pointer (If DE = FIB) + B = Attributes + IX = New file info block + RES: A = Error code + IX = New entry + + + + OPEN FILE HANDLE [_OPEN] + + IN: C = $43 + DE = Drive/path/file ASCIIZ of FIB + A = Mode: b0, no write b1, no read b2 inheritable + RES: A = Error code + B = New file handle + + + + And that's all folks. Sorry, I know, it aint much, but to be + hounest even I have got better things to like. Like sleeping, + for instance, because it's really terribly late... Till FD#29 + I guess, with -hopefully- a little more than this time... + +Tobias Keizer diff --git a/future_disk/28/the_pcm_sample_processor.md b/future_disk/28/the_pcm_sample_processor.md new file mode 100644 index 0000000..df45d97 --- /dev/null +++ b/future_disk/28/the_pcm_sample_processor.md @@ -0,0 +1,102 @@ + Bla bla bla bla + The PCM sample processor, the truth... + + ���� + ���� + ���� + ���� + + + + + Those good old days... I can remember them like it was + yesterday... Remember those stories in all the magazines when + the Turbo-R (ST) was released in Japan? A 28.8Mhz CPU, loads + of built-in software and a PCM-Samplechip. WOW!! Now it would + be possible to use samples with your music, or voice-recogni + sion. Yeah, righty... But still, the PCM isn't at all bad... + + +Music + + Were the music part is concerned, there aren't that many + options, unfortunately. Adressing the PCM chip takes too much + time for any other things to be done. Music + samples there- + fore isn't really an option. It is possible, but the sample + freuency has to be very low (No more than 12Khz) and there + will be a 60Hz rustle on the back of the sound. For something + like a drum, that's not too big a problem. But when it comes + to speach or something like that, you'll notice. + + The FD#25 game Ryu No Chie is a nice example of what I mean. + The sample frequency there was 8Khz, the music was played via + a slightly modified Moonblaster replayer in stereo mode. + Naturally, that wasn't the best a Turbo-R can do. For one, + the R800 wasn't on, and the R800 mode is at least 4 times + faster than the Z80 mode. Furthermore, the standard interrupts + where activated, which isn't too clever either. + +FREQUENCY + + The previously mentioned magazines told us the maximum sample + frequency on a Turbo-R was about 16KHz. Not at all true... In + ideal circumstances a sample (play!) frequency of 400KHz(!!!) + should not be a problem. But, like said, under ideal circum- + stances...Think OTIR in cases like these. However, under not + so ideal circumstances (read, a full-function PCM player) 16 + Khz is not the top by far. A sample frequency of 44KHz (CD + quality) should not give any problems either. However, the + big problem is recording those samples. As the samples are + recorded with only one bit, is takes a lot more CPU time to + record a sample, than it does to play one... Too bad... + + I haven't calculated all this, but I think recording should be + possible at a sample-rate of 24Khz, playing has very fiew + limits... + + +HOW TO PLAY A SAMPLE... + + Let's make a little program that plays a sample from $4000 + till $BFFF. Let's assume we do not need any interrupts, and + it is not possible to abort the process. Here's what you'd + get: + + BEGINN: LD HL,$4000 + LD BC,$8000 + LD A,%00000010 + OUT ($A5),A + + MAINLP: LD A,(HL) + OUT ($A4),A + INC HL + DEC BC + LD A,B + OR C + RET Z + JP MAINLP + + A small player like this one would put you well over the 44Khz + C quality. And when I say well over, I mean well over. If I + take a short look a this, it would put the sample rate at pro- + bably trice the frequence of that of a CD player... But, I + could be wrong... (I'm probably not though) Only remaining + problem is it won't be possible to record samples on a Turbo-R + at that frequence, you'll need quite a PC for that. Other pro- + blem is that at a frequence this high, 32kB's of sample isn't + really a lot to listen to. But still, that 16KHz really wasn't + all that accurate... + + Anyway, I suggest that those interested juggle a little with + this small source, and we'll continue next time, with a real + player with adjustable sample-frequency! How nice... + + By the way, that first OUT is to set the PCM chip for: + + Play sample, Don't send MIC in to speaker, Don't disable + Sound chips (Music/PSG), activate filter... + + Well, good luck... + And till next time... + +Tobias Keizer diff --git a/future_disk/30/advanced_basic.md b/future_disk/30/advanced_basic.md new file mode 100644 index 0000000..7199393 --- /dev/null +++ b/future_disk/30/advanced_basic.md @@ -0,0 +1,90 @@ + Daar gaan we dan weer: alweer zo'n programmeer-tekst...ditmaal Advanced Basic... + + + CURSUS ADVANCED BASIC + + + + Voor diegenen die niet genoeg hebben aan een handleiding en + wat meer voorbeelden willen, is hier een kleine cursus, die + ongeveer 3 a 4 delen zal beslaan. + + + I WANT TO USE WINDOWS + + Het belangrijkste gedeelte zijn natuurlijk de windows. In + Advanced BASIC zijn windows ALLEEN te gebruiken is scherm 0, + de schermbreedte moet minstens 41 zijn. Er kunnen maximaal + 16 windows tegelijk gebruikt worden, maar afhankelijk van de + grootte kunnen dat er minder worden. De maximale grootte van + een window is 80 bij 24, in dat geval worden de functietoet- + sen ook overschreven. De inhoud van zo'n window is 78 bij 22 + tekens. De minimale grootte van een window is 3 bij 3, de + inhoud is dan 1 bij 1. Als een window te groot is voor het + scherm, dan wordt dat (natuurlijk) gemeld. + + Een window is te maken met _WINDOW(X,Y,BREEDTE,HOOGTE). X en + Y geven de positie van de linkerbovenhoek aan en BREEDTE en + HOOGTE geven aan wat de naam al zegt. Een voorbeeld: + + 10 REM Mijn eerste window + 20 KEY OFF:_WINDOW(0,0,80,24) + 30 A$=INPUT$(1) + RUN + + Er verschijnt een window op locatie 0,0 die 80 bij 24 groot + is. + + WE WANT TEXT + + Met _PRINT(STR$) is het mogelijk om een string in de laatst + gemaakte window te printen. Als het einde van het window + bereikt is, scrollt de inhoud omhoog, tenzij een _SCROLLOFF + geven is. _SCROLLON doet het omgekeerde van _SCROLLOFF en + zorgt dus dat de inhoud wel kan scrollen. + + Maar goed, ik dwaal af. Eh, _PRINT dus. Het is niet mogelijk + om een getal op het scherm te zetten. Nou ja, niet direct. + Het is natuurlijk wel mogelijk om een getal om te zetten + naar een string. Een voorbeeld: + + 10 REM Mijn tweede window + 20 CLS:_WINDOW(0,0,80,3) + 30 _PRINT("Dit is mijn tweede window! Joepie!") + 40 LOCATE 0,3 + 50 A$=INPUT$(1) + RUN + + Er verschijnt een leuk windowtje met daarin de tekst zoals + aangegeven in regel 30. + + THATS NOT ALL + + De plek waar de tekst geprint moet worden in een window, kan + bepaald worden met _LOCATE(X,Y) en werkt hetzelfde als + LOCATE in gewoon BASIC. Als de plek buiten het scherm is, + komt er een foutmelding. Een klein voorbeeldje: _LOCATE(0,0) + zet de cursor in de linkerbovenhoek (hetgeen ook kan met + _HOME). + + Met _WCLS wordt de inhoud van de laatst gemaakte window + gewist. _RWIN haalt een window weg en herstelt datgene dat + achter het window zat. Het is ook mogelijk om alle windows + te wissen, dat kan met _RALLWIN. Ook hier wordt de + achtergrond weer hersteld. + + I LIKE SCROLLIN' AND MOVIN' + + Omdat mensen houden van scrollende dingen, zit er in + Advanced BASIC ook een optie daarvoor, nee, eigenlijk wel + vier, namelijk: _UP, _DOWN, _LEFT en _RIGHT. + + Deze commando's scrollen de inhoud van de laatst gemaakte + window in de aangegeven richting. + + WE WANT MORE + + Helaas, helaas, volgende keer meer! + + +Arjan Bakker diff --git a/future_disk/30/assembly_voor_beginners.md b/future_disk/30/assembly_voor_beginners.md new file mode 100644 index 0000000..22edbb2 --- /dev/null +++ b/future_disk/30/assembly_voor_beginners.md @@ -0,0 +1,106 @@ + De beginnertjes hebben het goed dit keer!!! Een gehele assymbly cursus voor jullie... + + + ASSEMBLY VOOR BEGINNERS + + + In deze rubriek komen routine's aan bod die nuttig zijn en + vaak gebruikt worden. Degenen die geen assembly kunnen, + hebben niets aan deze cursus. In dit eerste deel komt de + vermenigvuldigings-routine aan bod. + + + HOE DOEN WE DIT DAN? + + Okay, eerst eventjes laten zien hoe het dus niet moet, zoals + beginners het vaak doen (schaam je niet, ik deed het eerst + ook zo). Vermenigvuldigen gebeurt meestal botweg als + herhaald optellen van een getal. Bijvoorbeeld, 15 * 25 is + het resultaat van 25 + 25 + ... + 25 + 25 (in totaal 15 keer + het getal 25 en 14 keer het plusteken). Als source ziet dit + er zo uit: + + LD BC,15 + LD DE,25 + LD HL,0 + + MULUW: ADD HL,DE + DEC BC + LD A,B + OR C + JP NZ,MULUW + RET + + Natuurlijk, bij kleine getallen werkt dit wel snel, maar als + je grote getallen gebruikt, is een andere methode veel + sneller. + + + TERUG NAAR DE BASISSCHOOL + + Hoe pakken we het dan wel aan? Nou, ik zal even een voor- + beeldje geven hoe ik het geleerd heb op de basisschool. + + 15 + 25 + --- x + 5 * 15 = 75 + 2 * 150 = 300 + --- + + 375 + + Telkens als we een getal naar links gaan, dan vermenigvul- + digen we het eerste getal met 10. Op de MSX gaat het net zo, + maar nu moeten we even binair denken, dus vermenigvuldigen + we met 2, in plaats van 10. Hetzelfde voorbeeldje nog eens, + maar nu in het binaire talstelsel. + + 1111 = 15 + 11001 = 25 + -------- x --- x + 1 * 1111 = 1111 = 15 + 0 * 11110 = 0 + 0 * 111100 = 0 + 1 * 1111000 = 1111000 = 120 + 1 * 11110000 = 11110000 = 240 + -------- + ----- + + 101110111 = 375 + + Zoals je ziet, klopt dit als een bus. + + + NU OP DE MSX + + We gaan er even van uit dat de te vermenigvuldigen getallen + in BC en DE staan en dat het resultaat in HL komt. De source + ziet er dan als volgt uit: + + LD DE,25 ;De te vermenigvuldigen getallen. + LD BC,15 + + MULUW: LD HL,0 ;HL moet 0 zijn bij het begin + + MULUW1: SRL D ;Deel DE door 2. Als DE oneven was, + RR E ;wordt, de carry-flag gezet. + + JR NC,MULUW2 ;Carry-flag niet gezet? Niet optellen. + ADD HL,BC ;BC optellen bij resultaat. + + MULUW2: LD A,D ;Als DE 0 is, zijn we klaar. + OR E + RET Z + + SLA C ;Vermenigvuldig BC met 2. + RL B + JP MULUW1 ;Terug naar MULUW1 + + Met een CALL naar MULUW kun je de getallen in DE en BC snel + met elkaar vermenigvuldigen, het resultaat komt in HL. + + Als het goed is, is het nu duidelijk hoe het werkt. Zo niet, + lees de tekst dan nog maar eens over. + + Oja mensen, er staan .ASM files op deze FD. Dus dan kun je + het allemaal nog eens rustig bekijken (ASSEMBL1.ASM). + +Arjan Bakker diff --git a/future_disk/30/paint_in_ml.md b/future_disk/30/paint_in_ml.md new file mode 100644 index 0000000..e46c28a --- /dev/null +++ b/future_disk/30/paint_in_ml.md @@ -0,0 +1,78 @@ + Hoe kunnen we verven in ML???? Awel, na het lezen van deze tekst wordt het ons allemaal duidelijk... + + + PAINT IN ML + + + + Het is lastig om zelf een routine te maken die een vlak kan + inkleuren. Zo'n routine hoeft helemaal niet gemaakt te + worden, want in de SUB-ROM zit al zo'n routine. Deze is + echter niet zonder meer te gebruiken, want de routine is + voor de BASIC-interpreter. + + Om de routine te gebruiken, moet je een stukje BASIC + aanmaken in ML. In dit geval is dit niet lastig, tenminste, + als je de codes weet. + + + WAT IS ER NODIG + + De routine die voor het painten gebruikt wordt, heeft alleen + maar een klein stukje BASIC nodig, namelijk datgene dat + achter het commando PAINT komt. + + Dit stukje ziet er zo uit: + + db 40,28,0,0,44,28,0,0,41,44,28,0,0,44,28,0,0,0 + + De 40 geeft een haakje openen aan, 28 geeft aan dat de + volgende 2 bytes een integer vormen, 44 betekent komma, 41 + is haakje sluiten, de laatste nul betekent dat de regel is + afgelopen en daarmee zijn alle codes uitgelegd. De bytes + betekenen dus: + + (integer,integer),integer,integer einde regel + + Bij het commando PAINT zien we dus dat het betekent: + + (x,y),vulkleur,randkleur einde regel + + Het enige wat je nu moet doen is de nullen vullen met een + waarde en routine #0069 in het SUBROM aanroepen. De volgende + listing doet dat. + + + DE SOURCE + + ; Kleur een vlak in (alleen scherm 5,6,7 en 8) + ; Werkt misschien ook op scherm 10, 11 en 12 + ; In: DE = X-coordinaat + ; HL = Y-coordinaat + ; B = vulkleur + ; C = randkleur + ; Verandert: AF, BC, DE en HL + + paint: ld (dat1+2),de + ld (dat1+6),hl + ld a,b + ld (dat1+11),a + ld a,c + ld (dat1+15),a + ld hl,dat1 + ld ix,#0069 + call #015f + ret + + dat1: db 40,28,50,0,44,28,50,0,41,44,28,15,0,44,28,15,0,0 + ; PAINT ( X , Y ) , VK , RK + + + Zoals je ziet is het erg eenvoudig. Voor de luitjes die te + lui zijn om deze source even over te tikken, staat de source + (als het goed is)(NvdR: en alles is goed!!!) ook op de disk + onder de naam PAINT.ASM. + + +Arjan Bakker + diff --git a/future_disk/31/advanced_basic_2.md b/future_disk/31/advanced_basic_2.md new file mode 100644 index 0000000..d58caa7 --- /dev/null +++ b/future_disk/31/advanced_basic_2.md @@ -0,0 +1,221 @@ +Arjan vervolgt zijn cursus Advanced Basic... + +Cursus Advanced BASIC (2) + + Voordat ik weer wat commando's ga uitleggen, geef ik eerst + de bestelinformatie van Advanced BASIC 1.01. Smael was zo + dom dat hij vergat dat bij de recensie op FD #30 te zetten. + Maar goed, hier komt de informatie: + + Maak f 17,50 over op bankrekeningnummer 32.56.20.806 t.n.v. + Arjan Bakker te Hasselt o.v.v. AdvBASIC en je eigen naam en + adres. De bank is de Rabobank te Hasselt (Ov). + + +MORE ABOUT WINDOWS + + Nog niet alle windows-commando's waren behandeld de vorige + keer, dus komt hier de rest. + + Met _CSRLIN(adres) kun je de regel waar de cursor in een + window op staat opvragen. De regel komt dan in het opgegeven + adres terecht. + + Met _POS(adres) komt de x-positie van de cursor in een + window op het opgegeven adres terecht. + + _NWINDOW(adres) geeft het aantal gebruikte windows terug. + + _WINDATA(adres) geeft informatie over het window terug. Op + adres+0 staat de x-positie van het window, adres+1 is de + y-positie van het window, adres+2 de breedte en adres+3 de + hoogte. + + Een voorbeeld: + + 10 SCREEN 0 + 20 _WINDOW(0,0,80,5) + 30 _LOCATE(40,3) + 40 _CSRLIN(&HD000) + 50 _POS(&HD001) + 60 _NWINDOW(&HD002) + 70 _WINDATA(&HD003) + + Vanaf adres &HD000 komen de diverse data in het geheugen. + + +TRUUKJE + + Je kunt opgevraagde waardes ook direct in een variabele + stoppen. Dit gaat als volgt: + + _NWINDOW(VARPTR(N)) + + Het aantal aanwezige windows staat nu in variabele N. Let er + wel op dat de variabele N bestaat �n integer is, want anders + werkt het niet. Oh ja, deze truuk werkt niet bij _WINDATA. + + +MEER KLEUREN OP SCHERM 0 + + Screen 0 kan 4 kleuren tegelijk laten zien. Advanced BASIC + heeft hiervoor een viertal routines die dat wel erg + makkelijk voor jullie maken, namelijk: + + _COLOR(vg,ag,p1,p2). Vg is de voorgrondkleur, ag is de + achtergrondkleur, p1 is de periode dat de voorgrondkleur + zichtbaar is (in 1/50-seconden) en p2 is de periode dat de + achtergrondkleur zichtbaar is. + + Met _PUT(x,y,a) kun je een aantal karakters met andere + kleuren op het scherm zetten. X en y geven de x- en + y-positie weer en a is het aantal karakters. + + _UNPUT(x,y,a) doet het omgekeerde van _PUT, namelijk het + weghalen van de karakters. + + _CLS wist de alternatieve schermkleuren. + + Een voorbeeld: + + 10 SCREEN 0 + 20 _COLOR(15,0,15,15) + 30 _PUT(0,0,80*24) + 40 _UNPUT(0,0,80*24) + 50 GOTO 30 + + Het hele scherm wordt eerst gevuld met de alternatieve + schermkleuren en daarna worden deze weer gewist. Dan wordt + het scherm weer gevuld, gewist enz. enz. + + +TOT SLOT + + Tot slot komen hier nog wat simpele commando's. + + _CLBUF : Wist de toetsenbordbuffer. + _SNDOFF : Zet het PSG-geluid uit. + _CAPSON : Zet CAPS-lock aan. + _CAPSOFF : Zet CAPS-lock uit. + _INFO : Geeft wat informatie over Advanced BASIC. + _VERSION : Geeft het versie-nummer van Advanced BASIC. + + +DE VOLGENDE KEER + + De volgende keer komen de nieuwe disk-commando's aan bod. + Maar tot FD 32, dus maar! + + +Arjan Bakker +Arjan vervolgt zijn cursus Advanced Basic... + +Cursus Advanced BASIC (2) + + Voordat ik weer wat commando's ga uitleggen, geef ik eerst + de bestelinformatie van Advanced BASIC 1.01. Smael was zo + dom dat hij vergat dat bij de recensie op FD #30 te zetten. + Maar goed, hier komt de informatie: + + Maak f 17,50 over op bankrekeningnummer 32.56.20.806 t.n.v. + Arjan Bakker te Hasselt o.v.v. AdvBASIC en je eigen naam en + adres. De bank is de Rabobank te Hasselt (Ov). + + +MORE ABOUT WINDOWS + + Nog niet alle windows-commando's waren behandeld de vorige + keer, dus komt hier de rest. + + Met _CSRLIN(adres) kun je de regel waar de cursor in een + window op staat opvragen. De regel komt dan in het opgegeven + adres terecht. + + Met _POS(adres) komt de x-positie van de cursor in een + window op het opgegeven adres terecht. + + _NWINDOW(adres) geeft het aantal gebruikte windows terug. + + _WINDATA(adres) geeft informatie over het window terug. Op + adres+0 staat de x-positie van het window, adres+1 is de + y-positie van het window, adres+2 de breedte en adres+3 de + hoogte. + + Een voorbeeld: + + 10 SCREEN 0 + 20 _WINDOW(0,0,80,5) + 30 _LOCATE(40,3) + 40 _CSRLIN(&HD000) + 50 _POS(&HD001) + 60 _NWINDOW(&HD002) + 70 _WINDATA(&HD003) + + Vanaf adres &HD000 komen de diverse data in het geheugen. + + +TRUUKJE + + Je kunt opgevraagde waardes ook direct in een variabele + stoppen. Dit gaat als volgt: + + _NWINDOW(VARPTR(N)) + + Het aantal aanwezige windows staat nu in variabele N. Let er + wel op dat de variabele N bestaat �n integer is, want anders + werkt het niet. Oh ja, deze truuk werkt niet bij _WINDATA. + + +MEER KLEUREN OP SCHERM 0 + + Screen 0 kan 4 kleuren tegelijk laten zien. Advanced BASIC + heeft hiervoor een viertal routines die dat wel erg + makkelijk voor jullie maken, namelijk: + + _COLOR(vg,ag,p1,p2). Vg is de voorgrondkleur, ag is de + achtergrondkleur, p1 is de periode dat de voorgrondkleur + zichtbaar is (in 1/50-seconden) en p2 is de periode dat de + achtergrondkleur zichtbaar is. + + Met _PUT(x,y,a) kun je een aantal karakters met andere + kleuren op het scherm zetten. X en y geven de x- en + y-positie weer en a is het aantal karakters. + + _UNPUT(x,y,a) doet het omgekeerde van _PUT, namelijk het + weghalen van de karakters. + + _CLS wist de alternatieve schermkleuren. + + Een voorbeeld: + + 10 SCREEN 0 + 20 _COLOR(15,0,15,15) + 30 _PUT(0,0,80*24) + 40 _UNPUT(0,0,80*24) + 50 GOTO 30 + + Het hele scherm wordt eerst gevuld met de alternatieve + schermkleuren en daarna worden deze weer gewist. Dan wordt + het scherm weer gevuld, gewist enz. enz. + + +TOT SLOT + + Tot slot komen hier nog wat simpele commando's. + + _CLBUF : Wist de toetsenbordbuffer. + _SNDOFF : Zet het PSG-geluid uit. + _CAPSON : Zet CAPS-lock aan. + _CAPSOFF : Zet CAPS-lock uit. + _INFO : Geeft wat informatie over Advanced BASIC. + _VERSION : Geeft het versie-nummer van Advanced BASIC. + + +DE VOLGENDE KEER + + De volgende keer komen de nieuwe disk-commando's aan bod. + Maar tot FD 32, dus maar! + + +Arjan Bakker + diff --git a/future_disk/31/disk_io_in_basic.md b/future_disk/31/disk_io_in_basic.md new file mode 100644 index 0000000..2730f36 --- /dev/null +++ b/future_disk/31/disk_io_in_basic.md @@ -0,0 +1,236 @@ + Tobias leert ons wat meer over Disk I/O in BASIC... +BASIC, de drive laten ratelen... + + ���� + ���� + ���� + ���� + + + Dat de MSX BASIC een van de beste -zo niet de beste- BASIC + varianten is mag bekend zijn. Geen BASIC soort is zo goed uit- + gerust als MSX BASIC. Werkelijk alles is mogelijk. Ik geloof + dat de line-interrupt zo'n beetje het enige is dat BASIC niet + ondersteunt. Maar ook daar is indirect een oplossing voor. + Want MSX BASIC laat zich ideaal met machinetaal combineren. En + een drivertje is zo geschreven. + + Van muziek tot zelfs scroll routines, allemaal op de interrupt + erbij. Dat het er allemaal niet sneller op wordt mag duidelijk + zijn, maar het kan. Maar ook zonder die ML is er in MSX BASIC + een hele hoop mogelijk. + + + Disk I/O + + + Zo is ook het DISK I/O gedeelte van MSX BASIC niet misselijk, + van binaire files tot random-access file. Het kan allemaal. Om + precies te zijn heeft de DISK BASIC maar twee nadelen. Het eer + ste grote nadeel is dat er in BASIC geen data files zijn in te + laden. Elke file moet een HEADER hebben; BLOAD files dus. Dit + is een probleem waar ik in een latere aflevering nog wel eens + op terug kom. Een ander probleem is dat het in BASIC niet fat- + soenlijk mogelijk is om een directory op het scherm te zetten. + Dat kan eigenlijk alleen maar met het FILES commando. Het eer- + ste probleem is dan dus al dat de directory informatie op een + scherm moet kunnen passen. En onder DOS2 hoeft dat zeer zeker + niet het geval te zijn. Het tweede probleem is dat we vast zit- + ten aan de "layout" die BASIC ons voorschrijft. En manipulatie + van de directory is er al helemaal niet bij. + + Een veel gebruikte oplossing is om het scherm "uit" te zetten, + vervolgen het FILES commando te gebruiken, met een paar wel- + gemikte VPEEKs de data in variabelen te zetten om vervolgens + het oude scherm weer op te bouwen en de nieuwe data te printen + op het scherm. Aan een dergelijke kunstgreep kleven een aantal + nadelen. Ten eerste is het natuurlijk een weinig elegante, en + zeker niet makkelijke, oplossing. En ten tweede is zulks erg + lastig in een grafisch scherm. Er moet namelijk eerst naar het + tekst-scherm worden gegaan, waardoor bij terug keer naar het + grafische scherm heel page 0 gewist is. Allemaal niet erg han- + dig dus. Terwijl er een prima oplossing is...maar ja, onbekend + maakt onbemind... + + + DSKI$ & DSKO$ + + Met deze twee BASIC functies is het mogelijk om sectoren resp. + in te lezen en weg te schrijven. Bij de tweede functie volsta + ik met de syntaxis aangezien het schrijven van sectoren bij + het lezen van directories weinig waarde heeft. De syntaxis: + + A$ = DSKI$ (d,s) ; Voor het lezen van sector s van drive d + DSKO$ d,s ; Voor het schrijven van sector s op drive d + + Merk hier het verschil op tussen de syntaxis van beide instruc- + ties. De vorm van het DSKI$ commando doet vermoeden dat de + sector in de variabele A$ wordt gelezen of iets dergelijks. + Niets is echter minder waar. De sector wordt namelijk ingelezen + in een vaste buffer. En daar laten vrijwel alle BASIC boeken + het afweten. Geen van de boeken vermeld namelijk waar die + buffer dan wel in het geheugen te vinden is. + + De buffer staat overigens niet op een vaste plaats. De pointer + naar deze buffer uiteraard wel. En wel op adres $F351. Door + dus het adres van $F351 / $F352 af te plukken wordt dus het + adres van de sector buffer gevonden. Minder bekend is echter + dat dit adres ook weg te poken is. En daar komt de truuk. Want + we kunnen in plaats van het adres weg te poken veel beter zelf + ons adres bepalen. Dan zijn er immers veel minder adres-varia- + belen in ons programma nodig wat de snelheid nog wel eens ge- + voelig ten goede kan komen. + + POKE &HF351,&H00 : POKE &HF352,&HC0 + + Dit zal dus de meest logische oplossing zijn. Het adres $C000 is + namelijk een prima test adresje voor allerlei zaken. Voordeel + van de POKE methode is ook dat er ook andere machinetaal pro- + gramma's gebruikt kunnen worden zonder dat alles vast komt te + liggen. Gebruiken we bijvoorbeeld de MoonBlaster 1.4 BASIC + driver dan wordt er op adres $DA00 het een en ander aan gege- + vens neergezet. Doordat we precies weten waar onze data te- + recht komt hoeft er dus nooit iets mis te gaan. Want of Moon- + Blaster erg vrolijk wordt van een FAT in de STEPBF buffer weet + ik niet... + + + Directory structuur + + Deze keer denk ik dat het wijsheid is om eerst alleen de DOS 1 + directory structuur te bespreken. De DOS 2 structuur is name- + lijk flink wat moeilijker. Het eerste voordeel is dat de direc- + tory altijd op een vaste plaats te vinden is. Namelijk sector + 07-14 op een dubbelzijdige disk, de enkelzijdige disk laat ik + maar even voor wat het is, maar met de hierna volgende formule + is ook dat prima uit te rekenen. + + First DIR Sector = Number Of FATS * Sectors Per FAT + 1 + + Maar, hoe komen we dan aan die informatie? Simpel, uit de BOOT + sector. De BOOT sector (sector 0) is een sector waaruit geBOOT + kan worden, en waar informatie over de disk staat. Zo ook de + informatie die we voor onze formule nodig hebben. Om een duide- + lijker beeld te scheppen is het misschien verstandiger om maar + eerst eens een liniear beeld van een disk te scheppen. + + +Lees verder in deel 2... + + Tobias leert ons wat meer over Disk I/O in BASIC... +BASIC, de drive laten ratelen... + Deel 2 + ���� + ���� + ���� + ���� + + + Om een duidelijker beeld te scheppen is het misschien verstan- + diger om maar eerst eens een liniear beeld van een disk te + scheppen. + + BOOT Sector (00) + FAT Sectoren + Directory Sectoren + Data-Area Sectoren + + Om dus de eerste directory sector te berekenen moeten we weten + hoeveel FAT sectoren er zijn, en daar moet dan 1 bijop geteld + worden voor de BOOT sector. Nu blijkt dat een disk meer dan + ��n FAT kan hebben. Sterker nog, voor zover ik weet hebben + alle disks voor de zekerheid minimaal 2 kopien van de FAT. + Maar dat aantal hoeft niet vast te zijn. Zo is het geen pro- + bleem om 5 of 6 FAT kopi�n te hebben, hoewel dat niet gebruike- + lijk is. Ook is de lengte van een FAT niet vast. Op een dub- + belzijdige disk zal dat altijd 3 zijn, maar op een enkelzijdig + diskje meestal 2, terwijl een harddisk er weer veel meer heeft + dan 3. Dit alles staat dus in de bootsector. Ons eerste comman- + do zal dus + + A$ = DSKI$ (0,0) + + zijn, waarbij drive 0 voor de default diskdrive staat. Dan is + het belangrijk om te weten waar in de bootsector wat staat. + Het overzicht hieronder is niet helemaal correct, maar wel af- + doende. Zo zal het aantal bytes per sector op een MSX altijd + 512 zijn. Cluster informatie komt nu ook nog niet aan bod, dat + komt allemaal in een later deel wel. + + +16, 1 byte; Aantal FATs op disk + +17, 2 bytes; Aantal entries per directory + +21, 1 byte; Media Descriptor ($F8 = SS, $F9 = DS) + +22, 2 bytes; Aantal sectoren per FAT + + Als we dus de eerste directory sector willen weten is het on- + der staande stukje BASIC voldoende. + + 10 POKE&HF351,&H00: POKE&H352,&HC0: A$=DSKI$(0,0) + 20 NF=PEEK(&HC000+16): SF=PEEK(&HC000+22): FD=NF*SF + + Wederom eigenlijk niet correct. Zo kan een FAT in principe na- + melijk groter zijn dan 255 sectoren. Erg groot is die kans + echter niet; dat zou een behoorlijke harddisk moeten zijn. Nu + we dus de eerste directory sector weten kunnen we eindelijk be- + ginnen met uitlezen. Als we de structuur van een directory ken- + nen tenminste... + + +00, 11 bytes; Filenaam met extensie (geen .) + +11, 01 byte; Attribuut byte + +22, 02 bytes; Tijd "file-creation" + +24, 02 bytes; Datum "file-creation" + +26, 02 bytes; Eerste cluster + +28, 04 bytes; Lengte file (in bytes) + + Op dit moment is alleen het eerste nog maar belangrijk, de + filenaam. Nu staat er in een directory sector echt niet ��n + filenaam, sterker nog er staan er zelfs 16. Wederom maar weer + een klein stukje BASIC, dat spreekt immers boekdelen... + + 10 POKE&HF351,&H00: POKE&H352,&HC0: A$=DSKI$(0,0) + 20 NF=PEEK(&HC000+16): SF=PEEK(&HC000+22): FD=NF*SF + 30 ME=PEEK(&HC000+17): DS=FD: LS=FD+(ME/32): DIMF$(ME) + 40 ' Read Loop + 50 IFDS>LSTHENEND: ELSEA$=DSKI$(0,DS) + 60 FORLP=0TO15: AO=LP*32:F$(DE)="" + 70 FORL=0TO10: F$(DE)=F$(DE)+CHR$(PEEK(&HC000+AO+L): NEXTL + 80 DE=DE+1: NEXTLP: DS=DS+1: GOTO50 + + Dit stukje BASIC werkt in principe prima, maar heeft twee vrij + grote nadelen. Zo worden gewiste bestanden en lege directory + entries ook in de arrays geplaatst. En dat kost flink was ge- + heugen, en zal bijna nooit de bedoeling zijn. + + + $00 / $E5 + + Twee getallen die we in de filenaam kunnen tegenkomen, die een + speciale betekenis hebben. Zo betekent de eerste dat het einde + van de directory is bereikt, en de tweede dat het bestand ge- + wist is. Ook hier zullen we dus op moeten checken. Ons BASIC + programmaatje zal dus iets anders moeten worden. + + 10 POKE&HF351,&H00: POKE&H352,&HC0: A$=DSKI$(0,0) + 20 NF=PEEK(&HC000+16): SF=PEEK(&HC000+22): FD=NF*SF + 30 ME=PEEK(&HC000+17): DS=FD: LS=FD+(ME/32): DIMF$(ME) + 40 ' Read Loop + 50 IFDS>LSTHENEND: ELSEA$=DSKI$(0,DS) + 60 FORLP=0TO15: AO=LP*32: F$(DE)="" + 70 ' Do Check + 80 IFPEEK(&HC000+AO)=&HE5THENGOTO110 + 90 IFPEEK(&HC000+AO)=&H00THENEND + 100 FORL=0TO10: F$(DE)=F$(DE)+CHR$(PEEK(&HC000+AO+L): NEXTL + 110 DE=DE+1:NEXTLP:DS=DS+1:GOTO50 + + Dit is al iets beter. Uiteraard is dit dus een deelprogramma. + Een GOSUB naar dit stukje BASIC zou dus beter zijn. Maar, het + laat wel duidelijk zien hoe in BASIC een directory netjes, en + vlekkeloos kan worden uitgelezen. ON ERROR routines zijn name- + lijk geen probleem bij DSKI$ en DSKO$. + + De volgende keer gaan we eerst nog maar eens wat verder in op + de materie, om de keer daarna DOS 2 directories uit te lezen. + Met sub-directories nog wel!! Het is toch wat, die MSX BASIC! + + +Tobias Keizer diff --git a/future_disk/32/pascal_cursus_1_en.md b/future_disk/32/pascal_cursus_1_en.md new file mode 100644 index 0000000..b5f36fd --- /dev/null +++ b/future_disk/32/pascal_cursus_1_en.md @@ -0,0 +1,103 @@ +# Pascal (1) + +Koen asked me to write a course on PASCAL. And because I +think PASCAL is a well structured and nice language I +agreed. + + Before I begin the real work (the course), I will do a short + introduction. PASCAL (the language) is given the name of + Blaise Pascal the mathematician who lived from 1623 till + 1662. He was one of the great mathematicians that lived. He + laid down the basics for calculating changes. One of his + 'hobbies' was trying to create machines that did mathematics. + He created a machine that could do various calculations (not + only adding and subtracting) that was entirely mechanical + (try to imagine this). + + In about 1970 The name PASCAL (in capitals) was + 'reintroduced'. Professor Niklaus Wirth though it nice to + name his new programming language to the great mathematician. + I think most people have heard or read about PASCAL. PASCAL + has a lot of advantages compared to BASIC. PASCAL is almost + self documenting because of its structure. + + And now for the real thing. Lets begin with the structure of + a PASCAL program: + + PROGRAM program_name (INPUT,OUTPUT); + + CONST + {Constant definition} + + TYPE + {Type definition} + + VAR + {Variable declaration} + + {Procedure and function definition} + + BEGIN + {Main program} + END. + + All words in capitals are reserved words. This means that + this name cannot be used for something else (a variable for + instance), they have a special function in a program. PROGRAM + indicates that where about to make a PASCAL program. It is + followed by the name of the program and the words INPUT and + OUTPUT between brackets. The words INPUT and OUTPUT tell the + compiler that the program uses standard in- and output + (keyboard, screen). When working with files we will include + more between the brackets. + + After the program heading a block with constant, type and + variable declaration follows. PASCAL forces you to declare + all variables that you use in the program in advance. This + not as in BASIC where you can declare a variable when you + need it. + + After this the procedure and function declarations follow. + These declarations are equal to the 'program' declaration. + In a later course we will handle this. + + The last thing is a PASCAL program is the main program. The + main program is enclosed by BEGIN and END. + + That's it for the first course. I will leave you with a small + and simple PASCAL program. Try to compile and run it and see + if you can understand it. + +``` + PROGRAM simple (INPUT,OUTPUT); + + VAR + Value_1 : integer; + Value_2 : integer; + Result : integer; + + PROCEDURE input_value(VAR value:integer); + + BEGIN (* input_value *) + Write('Input a value : '); + Readln(value); + Writeln; + END; (* input_value *) + + BEGIN (* mainprogram *) + Writeln('Example program for PASCAL-course (1)'); + Writeln('FutureDisk'); + Writeln; + Writeln('Made by :'); + Writeln('Jeroen Smael'); + Writeln; + Writeln; + input_value(Value_1); + input_value(Value_2); + Result:=Value_1+Value_2; + Writeln(Value_1:1,' + ',Value_2:1,' = ',Result:1); + Writeln; + END. (* mainprogram *) +``` + + Jeroen 'PASCAL is fun' Smael \ No newline at end of file diff --git a/future_disk/32/pascal_cursus_1_nl.md b/future_disk/32/pascal_cursus_1_nl.md new file mode 100644 index 0000000..bf523d5 --- /dev/null +++ b/future_disk/32/pascal_cursus_1_nl.md @@ -0,0 +1,156 @@ +# Pascal (1) + + Men heeft mij gevraagd om een cursus PASCAL te schrijven. En + omdat ik PASCAL een goede, gestructureerde en leuke taal + vind, heb ik ja gezegd. + + Voordat ik ga beginnen met het echte werk, geef ik eerst een + korte inleiding over wat PASCAL precies inhoudt. PASCAL is + vernoemd naar de wiskundige Blaise Pascal die van 1623 tot + 1662 leefde. Blaise Pascal was ÇÇn van de grootste wiskundige + die de wereld gekend heeft. Hij heeft onder andere de + fundamenten gelegd van het kansrekenen. Maar het bekenste wat + Blaise Pascal heeft gedaan (buiten zijn bekende driehoek) is + het constru◊ren van een rekenmachine. Deze machine kon veel + rekenkundige berekeningen uitvoeren, en dat terwijl het + geheel alleen maar uit tandwielen en dergelijke bestond + (probeer je dat eens voor te stellen). + + Rond 1970 dook de naam PASCAL (geheel in hoofdletters) weer + op. Dit omdat ene Professor Niklaus Wirth het leuk vond om + zijn zojuist ontwikkelde programeertaal te vernoemen naar + Blaise Pascal. En deze taal is nu hÇÇl bekend. De meeste + mensen hebben er ervaring mee, of hebben er wel van gehoord. + Het voordeel van PASCAL boven BASIC is de gestructureerdheid. + Is het verplicht bij BASIC om commentaar te plaatsen (zeker + als iemand anders er iets van moet begrijpen) bij PASCAL wordt + de helft van de 'documentatie' door de gestructureerdheid van + de taal zelf verzorgd. Hiermee bedoel ik dat je er bij BASIC + een spagetti van kunt maken (met behulp van GOTO-instructies) + die niet te lezen is. Terwijl je bij PASCAL het programma + veel sneller doorziet door het inspringen (wordt later + duidelijk), de grotere verscheidenheid aan herhalingslussen + (WHILE, REPEAT en FOR) en het (bijna) niet voorkomen van + GOTO-instructies. + + Tot zover de inleiding. Nu gaan we dus echt beginnen. Dat + echt beginnen houdt in dat ik de globale structuur van een + PASCAL-programma ga uitleggen. + + De globale structuur van een PASCAL-programma is als volgt : + + PROGRAM programma_naam (INPUT,OUTPUT); + + CONST + {Constante definitie} + + TYPE + {Type definitie} + + VAR + {Variabelen declaratie} + + {Procedure en functie definitie} + + BEGIN + {Hoofdprogramma} + END. + + Alle woorden die hierboven met hoofdletters staan geschreven + zijn gereserveerde woorden. Dat wil zeggen dat deze naam niet + voor iets anders gebruikt kan worden en dat ze een speciale + functie hebben in een programma. Als we bovenaan beginnen dan + komen we als eerste het gereserveerde woord PROGRAM, gevolgd + door "programma_naam" tegen. Dit geeft voor de PASCAL- + compiler aan dat hier een programma met de naam + "programma_naam" begint. Verder volgen er de woorden INPUT en + OUTPUT (tussen haakjes). Deze woorden geven aan dat dit + programma gebruik maakt van de standaard in- en uitvoer + (toetsenbord en beeldscherm). Bij deze twee (gereserveerde) + woorden kunnen nog andere woorden staan, maar daar komen we + pas op als we het over file's gaan hebben. + + Na de programma heading volgt een blok waarin constantes, + types en variabelen worden gedeclareerd/gereserveerd. Het is + bij PASCAL zo dat je ALLE variabelen die je in het programma + gebruikt van te voren gedefinieerd (wat is het) en + gedeclareerd (hoe heet het) moet hebben. Dus niet zoals bij + BASIC "Oh, ik heb nog een variabele nodig. Laat ik maar iets + nemen." + + Na dit blok volgt er een blok waarin PROCEDURE's en + FUNCTION's gedeclareerd worden. Deze functies en procedures + zijn ook weer bloksgewijs opgebouwd en wel hetzelfde als een + programma. Dus ook met (functie/procedure) naam (en I/O + parameters), variabele blok, functie/procedure blok en een + hoofd blok. Hier zal ik ter zijner tijd nog uitgebreid op + terugkomen. + + Na al deze voorbereidende declaraties en definities, volgt + dan het uiteindelijke hoofdprogramma tussen de gereserveerde + woorden BEGIN en END, gevolgt door een punt. Deze punt is + voor de compiler het teken dat het programma klaar is. + + Voor deze keer wil ik besluiten met 2 programma's. Het eerste + programma CD's vind je zowel als tekstfile alsook als + gecompileerde versie (.COM file) op de FutureDisk. Het tweede + programma vind je hierbeneden. Bekijk beide programma's eens + en probeer eens te doorgronden wat ze doen. Bij onderstaand + programma mag dat geen problemen opleveren, terwijl dat bij + het programma CD's wel het geval zal zijn (behalve voor de + echte freaks onder ons). + + In de volgende afleveringen zal ik alle belangrijke elementen + van PASCAL de revue laten passeren (met veel voorbeelden EN + opgaves). Daarna zal ik recursie behandelen (ja, dat is heel + leuk) en als laatste zal ik nog aangeven wat TURBO PASCAL + precies inhoud (beter gezegt wat kan TURBO PASCAL wat + (standaard) PASCAL niet kan). + + Hier volgt een voorbeeld programma in PASCAL : +``` + PROGRAM simpel (INPUT,OUTPUT); + + VAR + Getal_1 : integer; + Getal_2 : integer; + Som : integer; + + PROCEDURE invoer_getal(VAR getal:integer); + + BEGIN (* invoer_getal *) + Write('Voer een getal in : '); + Readln(getal); + Writeln; + END; (* invoer_getal *) + + BEGIN (* hoofdprogramma *) + Writeln('Voorbeeld programma bij PASCAL-cursus (1)'); + Writeln('op de FutureDisk.'); + Writeln; + Writeln('Gemaakt door :'); + Writeln(' Jeroen ''KUBIE'' Smael'); + Writeln(' Galopiahof 6'); + Writeln(' 6215TK Maastricht'); + Writeln(' 043-437778'); + Writeln; + Writeln; + invoer_getal(Getal_1); + invoer_getal(Getal_2); + Som:=getal_1+getal_2; + Writeln(Getal_1:1,' + ',Getal_2:1,' = ',Som:1); + Writeln; + END. (* hoofdprogramma *) +``` +Jeroen 'PASCAL is leuk' Smael + + P.S. (1) Veel plezier met het uitpluizen van beide + programma's. + (2) Om beide programma's (uberhaupt elk PASCAL-programma) + te compileren heb je een PASCAL-compiler nodig. ik + vertrouw er echter op dat iedereen wel zoiets thuis + heeft liggen (op een oude floppie). + (3) Voor de echte freaks : Ik behandel alleen standaard + PASCAL. Het is namelijk een kwestie van een paar + functies bijleren als je overstapt van PASCAL naar + TURBO PASCAL. \ No newline at end of file diff --git a/future_disk/32/pascal_cursus_2_en.md b/future_disk/32/pascal_cursus_2_en.md new file mode 100644 index 0000000..1ac097c --- /dev/null +++ b/future_disk/32/pascal_cursus_2_en.md @@ -0,0 +1,83 @@ +# Pascal Course (2) + + Let's start programming. This course will handle + variables. One of the main differences between BASIC + and PASCAL is that in PASCAL you need to declare every + variable you use before using it. This is to tell the + compiler that you are going to use this variable AND to + tell the compiler how you are going to use it. That's right, + you need not only tell the compiler that you are going to use + a variable but also what kind of variable it is (integer, + real, etc). An example (the variable declaration is started + using the reserved word VAR): + + VAR + counter : integer; + value : real; + status : boolean; + + First use the reserved word VAR. Then on the next lines state + the name of the variable followed by a colon and it's type, + follow by a semi colon. The only restriction for variable + names is that they may not be a reserved word (like BEGIN, + END, VAR, etc). + + These are the standard types: + + - boolean (can be TRUE or FALSE) + - byte (no need to explain) + - integer (16 bit value, also called word) + - longint (32 bit value, also called longword) + - real (a not integer value) + - char (an ascii character) + - string (multiple characters) + - text (a file containing characters) + + These are all the standard types included in the modern + PASCAL versions. The last two (string and text) where not + included in the early versions of PASCAL, so check the + documentation of your compiler before using them. You can + also make your own variable types, but I will come to that in + a later course. + + How to use the variables? Here are some examples: + + value:=2; + character:='A'; + counter:=counter+1; + + Assigning a value to a variable is very simple. First name + the variable you want to assign the value to, then place the + 'equals' sign (:=) and then name the value to assign. The + last works just as in basic, the only restriction is that the + type may not change, e.g. don't assign a real to an integer. + + Besides the normal operators (+, -, *, (), AND, OR, XOR, + NOT), there are also 'functions' like CHR, ORD, ROUND, TRUNC, + ABS, ARCTAN, COS, EXP, FRAC, INT, LN, SIN, SQR, SQRT, etc. + Most of them you already know if you program in BASIC. If you + don't know them, then read a book about PASCAL. All of these + functions can be used, but again, DON'T CHANGE THE TYPE. + + Good to remember is that, when using integers, there are two + special functions you can use when dividing. Use DIV to + divide, and use MOD to get what's left after the division. + + That's it for this course. I will leave you with an + assignment. I will always try to leave you with an + assignment, because the only way of learning a computer + language, is by programming in the language. + + Assignment: + Write a program that asks for three prices of products. The + program must then calculate the total price with tax, the + total price without tax, the tax of each product and the + total tax. + + Use Readln(variable) to read a variable from the keyboard, + and use Writeln(variable) to write a variable to screen. + + Have fun and if you send your solution to me, I will ensure + that your solution is published next time. + +Jeroen 'Just program it' Smael \ No newline at end of file diff --git a/future_disk/32/pascal_cursus_2_nl.md b/future_disk/32/pascal_cursus_2_nl.md new file mode 100644 index 0000000..db7eba8 --- /dev/null +++ b/future_disk/32/pascal_cursus_2_nl.md @@ -0,0 +1,159 @@ +# Pascal Course (2) + + Wat is die Koen toch een etter. Nauwelijks ben ik een PASCAL + cursus begonnen of hij begint al met klagen. Vorige keer had + ik een leuke programmaatje op de disk laten zetten om je CD's + beter op te kunnen nemen, maar nee, voor meneer Dols is het + weer niet goed. + + Koen : Kan ik niet aangeven dat ik een 60 bandje heb? + Jeroen : Nee Koen, dat kan niet, dat was wat veel werk. + Koen : Wat is dat dan voor een stom programma, zorg er maar + voor dat dat volgende keer verbeterd is! + + Tja, en ik als goede onderdaan (Sahib, sahib) heb dat dus ook + maar gedaan. Ik hoop dus maar dat hij dit keer niets te + zeiken heeft(NvdR: ik heb thuis ook nog 100 minuten bandjes + Jeroen!) + + Maar genoeg over onze kleine sadist Koen. Nu gaan we over + naar het echte werk: programmeren. Als ik mij goed kan + herinneren, dan hebben we het vorige keer over de globale + structuur van PASCAL gehad. Nu gaan we het over variabelen + hebben. + + Een groot verschil tussen BASIC en PASCAL is dat het in + PASCAL verplicht is om alle variabelen die je gebruikt van te + voren aan te melden en te specificeren. Wat ik hiermee bedoel + is dat je de compiler duidelijk maakt hoe je variabelen heten + (jan, piet of klaas) en wat voor variabelen het zijn. Een + variabele declaratie zou er als volgt kunnen uitzien (de + variabele declaratie moet altijd vooraf gegaan worden door + het gereserveerde woord VAR): + + VAR + teller : integer; + getal : real; + status : boolean; + + De opbouw van deze declaratie mag wel duidelijk zijn. Eerst + komt er het gereserveerde woord VAR. Op de volgende regels + volgt de naam van de variabele die je gaat gebruiken gevolgd + door een dubbele punt en het type van de variabele. Aan de + naam van de variabele is eigenlijk maar een grote restrictie, + de naam mag geen gereserveerd woord (zoals BEGIN, END, VAR, + etc) zijn. De dubbele punt is verplicht. Het type van de + variabele kan vanalles zijn, maar ik beperk me hier tot de + standaard types : + + - boolean (kan de waarde TRUE of FALSE hebben) + - byte (spreekt voor zich) + - integer (16 bits geheel getal, ook word) + - longint (32 bits geheel getal, ook longword) + - real (een gebroken getal, lengte hangt af van de machine) + - char (een ascii karakter) + - string (een reeks ascii karakters) + - text (een file met ascii karakters) + + De punt-comma op het einde van de regel is verplicht (bijna + alle programma regels in PASCAL worden afgesloten met een + punt-comma). Naast bovengenoemde standaard types kun je ook + zelf types ontwikkelen (dagen van de week bijvoorbeeld), maar + daar kom ik later op terug. Voor ik het vergeet, de laatste 2 + types zouden wel eens niet kunnen werken, daar ze niet vanaf + de eerste PASCAL versies ge◊mplementeerd waren. Vanaf versie + 3 of hoger zouden ze echter aanwezig moeten zijn. + + Dan komen we nu bij de toewijzingen. Deze zijn zeer + gemakkelijk : + + getal:=2; + letter:='A'; + teller:=teller+1; + + Bovenstaande voorbeelden zijn erg simpel, maar geven het + principe goed weer. Een toewijzing wordt als volgt opgebouwd: + + Als eerste komt de variabele waar iets aan toegekend moet + worden. Dan volgt een dubbele punt met een "is-gelijk" + teken (spreek := uit als 'wordt'). En als laatste volgt de + waarde die de variabele moet krijgen. Deze waarde wordt + samengesteld zoals in BASIC, met een kleine restrictie: het + type mag (uiteraard) niet wijzigen. Dus als getal eerst een + integer was, dan mag deze niet door 'getal:=1.5' veranderd + worden in een real. Genoemde toewijzing zal resulteren in + een compiler fout of een run time error. + + Naast de gebruikelijke operators (+, -, *, (), AND, OR, XOR, + NOT) zijn er ook nog functies zoals CHR, ORD, ROUND, TRUNC, + ABS, ARCTAN, COS, EXP, FRAC, INT, LN, SIN, SQR, SQRT, etc. De + meeste namen duiden op soortgelijke functies uit BASIC, voor + meer details verwijs ik naar boeken over PASCAL. Genoemde + functies kunnen gewoon gebruikt worden in een toewijzing, als + men er maar aan denkt dat het type van de hele toewijzing + gelijk moet zijn aan het type van de variabele. + + Laatstgenoemde punt impliceerd dat er twee functies moeten + zijn om een getal te delen. Waarom? Omdat delen per definitie + een gebroken getal opleverd en dat dus niet een integer is. + Gehele getallen kunnen echter wel op elkaar gedeeld worden en + daarom is er een speciale functie nodig om integers te delen. + Deze speciale functie is de DIV functie (DIVide). De logisch + bijbehorende functie is MOD (MOD geeft de rest van de + deling). + + Zo, dat was het voor deze keer. Maar voor ik jullie weer + verlaat (ooohh) geef ik jullie nog een voorbeeldje en een + opgave om zelf te maken. Van het voorbeeld programmaatje ga + ik niet veel verklappen, bekijk het maar eens en probeer + (voor- dat je het laat uitvoeren) te beredeneren wat het + doet. Het voorbeeld programmaatje staat op de disk onder + PASCAL2.PAS (dan hoeven jullie het niet over te tikken). + + De opgave daar wil ik iets anders mee doen. Als iemand zo gek + is om het te proberen, het op te lossen en de oplossing op te + sturen, dan beloof ik die persoon dat zijn oplossing volgende + keer geplaatst wordt. En om het nog aantrekkelijker te maken + vermelden we de naam van de persoon die de oplossing heeft + ingestuurd (HÇ Koen, wedje dat nu niemand meer iets instuurt. + Kun je tenminste niet weer kankeren dat je niet alles op de + disk kunt plaatsen wegens plaatsgebrek). + + Zo, genoeg getypt, nu de opgave : + Schrijf een programma dat om 3 netto prijzen van artikelen + vraagt. Bereken aan de hand van die prijzen : De BTW per + artikel, het totaal betaalde BTW bedrag, de totale BRUTO en + NETTO prijs van de drie artikelen. + + Aangezien ik nog niets heb gezegd over in- en uitvoer van + variabelen via toetsenbord en beeldscherm, verwijs ik naar + het voorbeeld programma. Door dit goed te bekijken moet het + mogelijk zijn om iets soortgelijks te construeren. + + Veel plezier en tot volgende keer, + +Jeroen 'KUBIE' Smael +Galopiahof 6 +6215TK Maastricht +Tel : 043-3437778 ('s weekends) +Tel : 040-2261521 (door de week) + +Stuur de oplossingen van de puzzle ook naar dit adres!! + + P.S. (1) Om een nieuwe programmeertaal te leren moet je zelf + een heleboel oefenen en uitzoeken, daar leer je + tenslotte het meeste van. Daarom kauw ik niet alles + voor, maar laat een heleboel aan jezelf over. + (2) Boeken die je kunt raadplegen zijn onder de VELE + andere : K.L. Boon / PASCAL voor iedereen / Kluwer / + ISBN 90.201.1425.5 --- Findley / PASCAL Inleiding + tot gestructureerd programmeren / Kluwer / ISBN + 90.201.1991.5 + (3) Let ook op de programmeerstijl die ik in het + voorbeeldprogramma gebruik. Er is geen standaard + voor, maar mijn stijl is wel gestructureerd en dat + bevorderd de leesbaarheid. + (4) Dankzij Koen staat er dus ook een verbeterde versie + van het CD programma op de disk (CD2.PAS / CD2.COM). + Veel plezier daarmee (nog iets te mekkeren, Koen?). + (NvdR: Ja, Jeroen: Bl◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊◊h!) \ No newline at end of file diff --git a/future_disk/32/screen_4.md b/future_disk/32/screen_4.md new file mode 100644 index 0000000..0cb07cd --- /dev/null +++ b/future_disk/32/screen_4.md @@ -0,0 +1,194 @@ +# Screen 4 + + + Bij alle besprekingen van de MSX2 video chip, wordt er altijd + aandacht besteed aan de bitmapped modes, screen 5 tot en met + acht, maar nooit aan de mogelijkheden van Screen 4. + Waarschijnlijk is dit, omdat Screen 4 te zeer een MSX1 + verleden heeft. Toch zijn de mogelijkheden van deze + schermmode groot en kunnen er leuke dingen mee gedaan worden. + +## Opbouw + + Screen 4 is een pattern screen. Dit wil zeggen, dat het + scherm niet bestaat uit pixels, maar wordt opgebouwd uit + informatie uit verschillende tabellen. Dit klinkt erg + moeilijk, maar het komt erop neer dat wanneer je pixel (0,0) + wit wil maken, je eerst in de patroon tabel een volgend + patroon aanmaakt: + + &b10000000 + &b00000000 + &b00000000 + &b00000000 + &b00000000 + &b00000000 + &b00000000 + &b00000000 + + Plaatsen we dit patroon in het begin van de eerste + patroontabel (er zijn er meer) dan krijgt dit patroon nummer + nul. Vervolgens vullen we de kleur tabel met dit patroon: + + &hf0 + &h00 + .. (volmaken tot de acht) + &h00 + + En tot slot plaatsen we in de naam tabel op de eerste positie + een nul en we zien een witte pixel. + Hieruit blijkt al dat het dus een stuk moeilijker is om te + tekenen op Screen 4. + + Samenvattend komen we nu uit bij de drie tabellen: + + +## PATROON TABEL + + De locatie van de patroontabel in het videogeheugen kan + worden ingesteld middels register 4: + + Msb 7 6 5 4 3 2 1 0 + Reg 4 0 0 A16 A15 A14 A13 1 1 + + Als je de patroon tabel dus op adres nul wil laten beginnen, + dan laad je register 4 met %b11. + + De patroontabel bestaat uit drie blokken van elk 256 + patterns. Hiermee is het mogelijk om het gehele scherm te + vullen. Het eerste block bevat de informatie voor de de + bovenste 64 beeldlijnen (0-63). Hieruit volgt al ÇÇn van de + grappige eigenschappen van Screen 4, als je een patroon + binnen lijn 0-63 en lijn 64-127 wil gebruiken, dan moet je + dit patroon twee keer defini◊ren. + + De opbouw van het patroon ziet er als volgt uit: + &01 + Aanvullen tot acht + &00 + + Zoals al duidelijk wordt, kun je maar twee kleuren in een + acht bij acht blokje gebruiken. Je hebt enkel variatie 1 en + 0. Dankzij de kleuren tabel echter kun je per lijn de kleur + veranderen. Het idee komt overeen met dat van sprites. + + Nog een leuke bij de patroontabel. Toen ik met vdp23 in de + weer ging op een Screen 4 scherm, kreeg ik met geen + mogelijkheid de lijnen van (192-255) gevuld. Maar toen ik + effe naar de layout keek en erg simpel even wat adressen in + het video geheugen opschoof, viel op dat de patroontabel + eigenlijk uit vier blokken bestaat: (0-63),(64-127),(128- + 191),(192-255). Maar omdat dit alleen kan als je meer dan 16k + video geheugen hebt, wordt dit nooit in een of ander databoek + vermeld. + + +## KLEURENTABEL + + De kleurentabel bepaalt welke kleuren geassoci◊erd moeten + worden met de nul en een in de patroon tabel. De plaats van + de kleurentabel bepaal je met registers 3 en 10: + + Msb 7 6 5 4 3 2 1 0 + Reg 3 A13 1 1 1 1 1 1 1 + Reg 10 0 0 0 0 0 A16 A15 A14 + + De kleurentabel bestaat opnieuw uit drie (vier dus) blokken + en is per blok als volgt opgebouwd: + + &00 + aanvullen tot acht + &00 + + Waarbij de eerste nibble de kleur van de als 1 gedefini◊erde + patronen bepaald en de laagste nibble de kleur van de als 0 + gedefini◊erde. Dit kun je per lijn wijzigen. + +## NAAM TABEL + + Nu hebben we de kleuren en de patronen, dan volgt tot slot + nog de naam tabel. De plaats van deze tabel in het geheugen + kun je bepalen met register 2. + + Msb 7 6 5 4 3 2 1 0 + Reg 2 0 A16 A15 A14 A13 A12 A11 A10 + + In deze tabel bepaal je op welke plaats je gedefini◊erde + patronen terecht moeten komen. Positie nul in de tabel komt + overeen moet coordinaat (0,0). Positie ÇÇn komt overeen moet + (8,0) enz. In deze bytes zet je het patroon nummer. Je hoeft + je geen zorgen te maken om de kleurentabel, want deze is + automatisch gekoppeld aan de patroontabel. Uiteraard bestaat + deze tabel ook weer uit drie (vier) delen. + + Zo, nu hebben we alle data van screen4 besproken, laten we + eens kijken hoe het in de praktijk werkt door middel van ÇÇn + van de meest aansprekende voorbeelden: Space Manbow. + + Als we Space Manbow opstarten moeten we even door wat scherm + 5 plaatjes heen en komen we in het prachtige speelscherm. + + Wat zien wij nu: + + Een stilstaande bovenkant (screen 5, line interrupt) + Een sterren scroll (screen4) + Een scrollend middenveld (Screen 4) + Een rap scrollend benedenveld (Screen 4) + Een lading sprites. + + Geweldig! + + De sterretjes worden wel heel simpel gedaan, door voortdurend + het patroon te wijzigen. Een simpele RLCA instructie doet + hier wonderen. Het middenveld wordt gescrolled door de + naamtabel voortdurend te verplaatsen en tot slot de onderste + lijn wordt bewerkt door gewoon twee keer zo snel de naam + tabel door te schuiven. + + Zoals je al altijd gezien had, is het resultaat verbluffend, + het spel lijkt eerder van de SuperNes te komen, dan van een + simpele MSX. + Aangezien Konami een stel designers in dienst had die een + lange staat van dienst op de MSX 1 achter de rug hadden, is + er goed gebruik gemaakt van de mogelijkheden van Screen 4. + Als je goed kijkt, valt je namelijk op dat er echt gespeeld + is met de twee kleuren per 8x8 blokje. Het is vergelijkbaar + met het ontwerpen van sprites. + Ook in de hogere levels is leuk ingehaakt op de mogelijkheden + van pattern screens. Zo noem ik de laserstralen van het boss + monster in het laatste level. Als je dat met een line + commando in screen 5 zou willen doen, zou dat heel erg traag + worden. Op schermpje vier edit je een patroontje en met wat + gespeel in de naamtabel heb je schermvullende actie. + + Een ander leuk voorbeeld van Screen 4 is FireHawk. Het intro, + met de naar achter vliegende letters is ook op scherm vier + gemaakt. Waarom? Omdat scherm vier snel is en het weinig + geheugen in beslag neemt. Ook het hele spel loopt in Screen + 4 + en scrollt met stappen van 8 bij 8. + + Waarom gebruikt dan niemand scherm 4? Simpel: + + ? Je moet een heel goede tekenaar zijn + ? Je moet een heel goed tekenprogramma hebben + ? Je moet heel goede dataveld editors hebben + ? Je moet iemand met een MSX1 verleden zijn + + Aangezien er bijna niemand aan deze eisen voldoet, maakt dan + ook niemand iets op Screen 4. Alleen Jan van Valburg heeft + ooit twee Screen 4 spellen gemaakt, Gianna Sisters en + Retaliator. Oh ja, Çn ANMA natuurlijk met Troxx. + + Dus, als je ooit nog een Space Manbow wilt maken: leer teke- + nen met beperkingen en gebruik allerlei truukjes om de + mensen te laten geloven dat ze naar een Super Nes zitten te + kijken. + + Succes + + +Jan-Willem van Helden + + P.S. Ik probeer op de volgende FD nog iets leuks te doen met + Screen 4. Let op! \ No newline at end of file diff --git a/future_disk/33/advanced_basic_3.md b/future_disk/33/advanced_basic_3.md new file mode 100644 index 0000000..b2e2cf9 --- /dev/null +++ b/future_disk/33/advanced_basic_3.md @@ -0,0 +1,92 @@ +Arjan vervolgt zijn cursus Advanced Basic... + Cursus Advanced BASIC (3) + + + Advanced BASIC heeft een aantal extra diskcommando's die het + leven heel wat makkelijker maken voor de BASIC-programmeur. + + Een van die commando's is _DISKRD(drive,start,aantal,adres). + Dit commando laadt een aantal sectoren achterelkaar. De + variabele drive staat hier voor de drivenummer (0 = A, 1 = B + enz.), start is de eerste sector, aantal is het aantal + sectoren en adres is het adres waar de inhoud van de gelezen + sectoren terecht moet komen. + + Als er een _DISKRD is, is er natuurlijk ook een _DISKWRT, + die een aantal sectoren achter elkaar schrijft. De syntax is + hetzelfde als bij _DISKRD. + + Een voorbeeldje: + + 10 _DISKRD(0,0,16,&H9000) + 20 _DISKWRT(1,0,16,&H9000) + RUN + + Dit programma laadt de eerste 16 sectoren van drive A en + slaat ze op op drive B. + + +BESTANDEN + + Bepalen welke bestanden er op een diskette staan is altijd + lastig geweest onder BASIC. Advanced BASIC heeft daar 3 + commando's voor. Ten eerste is er _FILENAME(VAR$), welke + bepaald naar welke bestanden er moet worden gezocht. VAR$ + MOET overigens minstens 11 letters lang zijn en het *-teken + mag niet gebruikt worden. + + Om nu het eerste bestand dat op de diskette staat te + achterhalen, is er _SFFILE(VAR$) (VAR$ is weer minstens 11 + tekens lang). De eerste filenaam die voldoet aan de met + _FILENAME(VAR$) opgegeven filenaam, komt nu in VAR$ terecht. + Alle volgende filenamen kunnen met _SNFILE(VAR$) geladen + worden. Als er 2 keer achter elkaar dezelfde filenaam + gelezen is, heb je alle filenamen gehad. + + Een voorbeeld: + + 10 _FILENAME("????????BAS") + 20 F$=SPACE$(11):G$=F$ + 30 _SFFILE(F$):IF G$=F$ THEN END + 40 PRINT F$:G$=F$ + 50 _SNFILE(F$):IF G$=F$ THEN END + 60 GOTO 40 + RUN + + Dit programma laat alle bestanden met de extensie .BAS zien. + + +DRIVES + + Het aantal aangesloten drives is te bepalen met het commando + _NDRIVES(adres). Het aantal drives komt dan op het opgegeven + adres terecht. + + De huidige drive is op te vragen met _GETDRIVE(adres). Als + je de huidige drive wilt veranderen, kun je _SETDRIVE(drive) + gebruiken. + + Een voorbeeld: + + 10 _GETDRIVE(&H9000) + 20 PRINT "De huidige drive is ";CHR$(PEEK(&H9000+65)) + 30 _NDRIVES(&H9000) + 40 PRINT "Er zijn";PEEK(&H9000);" drives aangesloten" + 50 PRINT "Welke drive moet de default-drive worden?"; + 60 INPUT "In letters graag";D$ + 70 D=ASC(D$) OR 32:D=D XOR 32:D=D-65 + 80 _SETDRIVE(D) + RUN + + Dit programma geeft de defaultdrive en het aantal drives + weer en daarna mag je de nieuwe defaultdrive zelf bepalen. + + +TOETJE + + Als toetje zijn er nog de commando's _VERIFYON en _VERIFYOFF + welke de controle op schrijffouten respectievelijke aan- en + uitzetten. + + +Arjan Bakker diff --git a/future_disk/33/assembly_cursus_2.md b/future_disk/33/assembly_cursus_2.md new file mode 100644 index 0000000..20831ef --- /dev/null +++ b/future_disk/33/assembly_cursus_2.md @@ -0,0 +1,109 @@ + De assembly cursus gaat eindelijk verder... +ASSEMBLY CURSUS (2) + + + Hier is dan eindelijk het tweede deel van de assembly + cursus. Dit maal bespreek ik een string-search routine. De + routine is zo simpel mogelijk gehouden door wildcards etc. + gewoon niet toe te staan. Het moet echter simpel zijn om de + wildcard '?' te implementeren. + + +DE INVOER + + De routine heeft 3 variabelen nodig, namelijk het adres waar + met zoeken moet worden begonnen (HL), het aantal te + onderzoeken bytes (BC) en het beginadres van de te zoeken + string (DE). De te zoeken string moet afgesloten worden met + #FF, evenals de strings in het geheugen. + + +DE ROUTINE + + Hier komt dan de routine, met tussendoor wat uitleg. + + SEARCH: PUSH DE + INC HL + + SEARCH initialiseert de zoek-routine. DE moet bewaard + worden, omdat deze wordt gebruikt om bij te houden op welke + plek in de string we zitten. CPI verhoogt HL altijd, maar + als de bytes niet hetzelfde zijn, moet dat juist niet. + Daarom wordt HL alvast verhoogd, omdat HL in STRSRC verlaagt + MOET worden. + + STRSRC: POP DE + PUSH DE + DEC HL + LD A,(DE) + + SRCHF: CPIR + JP Z,FOUNDF + + STOP: LD A,255 + POP DE + RET + + Eerst wordt de pointer weer opgehaald en bewaard. HL wordt + verlaagd omdat CPI HL altijd verhoogt, terwijl dat juist + niet altijd nodig is. Dan wordt het eerste teken van de + string geladen en CPIR zoekt dan net zolang totdat het teken + gevonden is. Als het teken gevonden is, wordt er gesprongen + naar de routine die de volgende bytes onderzoekt en anders + stopt het programma met 255 in de accu om aan te geven dat + de string niet gevonden is. + + FOUNDF: LD (STRADR),HL + + Adres van string wordt bewaard, omdat de string niet gelijk + hoeft te zijn als de zoekstring. + + INC DE + LD A,(DE) + SRCHN: CPI + JP NZ,STRSRC + + Volgende teken wordt geladen en vergeleken. Als ze niet + gelijk zijn, wordt er teruggegaan naar de routine die het + eerste teken zoekt. + + LD A,B + OR C + JP Z,STOP + + Als alle bytes geweest zijn, stopt het programma. + + INC DE + + Volgende teken. + + LD A,(DE) + CP #FF + JP NZ,SRCHN + LD A,(HL) + CP #FF + JR NZ,STRSRC + + Er wordt gekeken of de zoekstring aan het einde is. Als dat + niet zo is, wordt er verder gegaan met vergelijken. Als dat + wel zo is, wordt er gekeken of de string in het geheugen ook + aan het einde is. Als dat niet zo is, wordt er overnieuw + begonnen met zoeken. + + XOR A + LD HL,(STRADR) + DEC HL + POP DE + RET + + STRADR: DEFW 0 + + Accu wordt 0 om aan te geven dat het zoeken gelukt is. Het + adres van de string wordt geladen en DE wordt teruggehaald + ivm met RET. + + Zo, dit was de routine. Voor de mensen die het willen + gebruiken, staat de routine ook op disk onder de naam + STRSRCH.ASM. Tot de volgende keer! + +Arjan Bakker diff --git a/future_disk/33/bits_en_bull.md b/future_disk/33/bits_en_bull.md new file mode 100644 index 0000000..4d25e1b --- /dev/null +++ b/future_disk/33/bits_en_bull.md @@ -0,0 +1,259 @@ + Programmeercursi zat dit keer... + The lamest ML course in town... Bits and bullshit... + + + ���� + ���� + ���� + ���� + + + De DOS2.x text van deze keer was wat aan de korte kant, dus + ik ga me maar eens op ML storten. En dit keer eens wat and- + ers. We gaan het BIT commando helemaal uitdiepen. ALLES wat + we er maar over moeten weten komt deze keer aan bod. Hou je + vast dus, wat dit kon nog wel eens een flinke text worden. + + +She said byte me... + + BIT kan maar voor een ding gebruikt worden.. Om de toestand + van een byte te bepalen. Door het juiste BIT commando te ge- + bruiken kunnen we de toestand van alle bitjes in een byte + afzonderlijk bepalen. Uiteraard kan dit op vele manieren en + lang niet altijd zal BIT de handigste zijn, maar BIT heeft + wel een flink aantal mogelijkheden. + + +So I bit her... + + [BIT nummer,slachtoffer] Hierbij staat nummer voor het bit- + nummer dat natuurlijk 0 tot 7 mag zijn. Het slachtoffer van + deze bewerking kan werkelijk van alles zijn maar daar komen + we zometeen op terug. BIT doet maar een belangrijk ding; de + zero-flag wel of niet zetten... En dat wilden we nu net van + het slachtoffer weten. + + +I must have misunderstood... + + Eerst alle mogelijkheden op een rijtje. Ik zal eerst de mo- + gelijke BIT instructies maar eens op een rijtje zetten. Dan + komt de onafhankelijke beschrijving later. + + BIT b,(HL) + BIT b,(IX + n) + BIT b,(IY + n) + BIT b,r + + +'Coz she popped me dead... + + Nou, dat viel toch reuze mee of niet??? Laten we eerst alle + instructies eens afzonderlijk onder de loep nemen, dan komt + daarna de volledige lijst met tijdsduur etc wel... + + +BIT b,(HL) + + Bit b van de geheugen locatie geadresseerd door HL wordt ge- + test en de zero-flag wordt overeenkomstig met het resultaat + geset. De bbb in de object codes komen overeen met het geko- + zen bit voor de test. + + OBJ CODE: Byte 1: %11001011 ($CB) + Byte 2: %01bbb110 ( - ) + + +BIT b,(IX + n) + + Bit b van de geheugen-locatie geaddresseerd door de inhoud + van register IX plus de verplaatsing [n] wordt getest en de + zero-flag wordt overeenkomstig met bit b geset. De n in de + object code staat voor de opgegeven verplaatsing. + + OBJ CODE: Byte 1: %11011101 ($DD) + Byte 2: %11001011 ($CB) + Byte 3: %nnnnnnnn ( n ) + Byte 4: %01bbb110 ( - ) + + +BIT b,(IY + n) + + Bit b van de geheugen-locatie geaddresseerd door de inhoud + van register IY plus de verplaatsing [n] wordt getest en de + zero-flag wordt overeenkomstig met bit b geset. + + OBJ CODE: Byte 1: %11011101 ($FD) + Byte 2: %11001011 ($CB) + Byte 3: %nnnnnnnn ( n ) + Byte 4: %01bbb110 ( - ) + + + BIT b,r + + Bit b van register r wordt getest en de z-flag wordt over- + eenkomstig geset. De r in de object code staat voor de bin- + aire code achter elk register. + + r: A %111 B %000 C %001 D %010 E %011 H %101 L %101 + + OBJ CODE: Byte 1: %11001011 ($CB) + Byte 2: %01bbbrrr ( - ) + + +And that's it... + + En dat was het al weer. Tijd dus om de timing van deze type + BIT instructies eens te bekijken. Ik zal de timing in mach- + ine cycli geven en in T-States. Om dus de duur van een in- + structie te berekenen moet het aantal T-States vermenigvul- + digd worden met de duur van een cyclus... De M-Cycli hebben + daar dus niets mee te maken. De snelheid in miliseconden is + variabel (ligt aan het type processor; Z80a/Z80b/Z80h/R800) + dus die geef ik niet op. De R800 is overigens een apart ge- + val... Daar gaat het namelijk niet om de clock snelheid van + 7MHz maar om het feit dat de R800 ook nog eens minder Cycli + nodig heeft om een BIT instructie uit te voeren... Zeker de + instructie met de index registers gaan flink wat sneller!!! + Hier is de R800 dus op twee punten sneller dan de Z80a. Ten + eerste omdat de clock snelheid hoger ligt en ten tweede om- + dat de R800 minder T-States nodig heeft. + + + | Instructie | M Cylci | T States | + +------------------+-------------+---------------+ + | BIT b,(HL) | 3 M Cycli | 12 T States | + | BIT b,(IX + n) | 5 M Cycli | 20 T States | + | BIT b,(IY + n) | 5 M Cylci | 20 T States | + | BIT b,r | 2 M Cylci | 08 T States | + + +That's all folks... + + En dan zit het er echt op!! Op een ding na natuurlijk... De + lijst van alle mogelijke bit instructies en hun object code + natuurlijk. Om de routine van Smael niet al te erg te tar- + ten zal ik hiervoor maar een aparte text typen, lees dus in + deel twee verder voor alle instucties, met alle OBJ codes. + + Voor nu, slaap lekker, en tot de volgende FD... + + + Dhr Keizer...ah whatever ik weet het ook niet + To byte, bit, bit.... + + ���� + ���� + ���� + ���� + + + Okay, beloofd is beloofd, alle mogelijke instructies, met + alle objectcodes... Tja, hoe krijg je zo'n diskmagazine an- + der vol tegewoordig. (Hint: Met lezersbrieven...) Oh wacht, + laat ik wel oppassen met wat ik zeg.. ik ga natuurlijk niet + alle 256 mogelijke verplaatsingen bij de indexregisters op- + geven; dan wordt Smael z'n routine echt depressief... + + BIT 0,(HL) CB 46 + BIT 0,(IX+d) DD CB 05 46 + BIT 0,(IY+d) FD CB 05 46 + BIT 0,A CB 47 + BIT 0,B CB 40 + BIT 0,C CB 41 + BIT 0,D CB 42 + BIT 0,E CB 43 + BIT 0,H CB 44 + BIT 0,L CB 45 + + BIT 1,(HL) CB 4E + BIT 1,(IX+d) DD CB 05 4E + BIT 1,(IY+d) FD CB 05 4E + BIT 1,A CB 4F + BIT 1,B CB 48 + BIT 1,C CB 49 + BIT 1,D CB 4A + BIT 1,E CB 4B + BIT 1,H CB 4C + BIT 1,L CB 4D + + BIT 2,(HL) CB 56 + BIT 2,(IX+d) DD CB 05 56 + BIT 2,(IY+d) FD CB 05 56 + BIT 2,A CB 57 + BIT 2,B CB 50 + BIT 2,C CB 51 + BIT 2,D CB 52 + BIT 2,E CB 53 + BIT 2,H CB 54 + BIT 2,L CB 55 + + BIT 3,(HL) CB 5E + BIT 3,(IX+d) DD CB 05 5E + BIT 3,(IY+d) FD CB 05 5E + BIT 3,A CB 5F + BIT 3,B CB 58 + BIT 3,C CB 59 + BIT 3,D CB 5A + BIT 3,E CB 5B + BIT 3,H CB 5C + BIT 3,L CB 5D + + BIT 4,(HL) CB 66 + BIT 4,(IX+d) DD CB 05 66 + BIT 4,(IY+d) FD CB 05 66 + BIT 4,A CB 67 + BIT 4,B CB 60 + BIT 4,C CB 61 + BIT 4,D CB 62 + BIT 4,E CB 63 + BIT 4,H CB 64 + BIT 4,L CB 65 + + BIT 5,(HL) CB 6E + BIT 5,(IX+d) DD CB 05 6E + BIT 5,(IY+d) FD CB 05 6E + BIT 5,A CB 6F + BIT 5,B CB 68 + BIT 5,C CB 69 + BIT 5,D CB 6A + BIT 5,E CB 6B + BIT 5,H CB 6C + BIT 5,L CB 6D + + BIT 6,(HL) CB 76 + BIT 6,(IX+d) DD CB 05 76 + BIT 6,(IY+d) FD CB 05 76 + BIT 6,A CB 77 + BIT 6,B CB 70 + BIT 6,C CB 71 + BIT 6,D CB 72 + BIT 6,E CB 73 + BIT 6,H CB 74 + BIT 6,L CB 75 + + BIT 7,(HL) CB 7E + BIT 7,(IX+d) DD CB 05 7E + BIT 7,(IY+d) FD CB 05 7E + BIT 7,A CB 7F + BIT 7,B CB 78 + BIT 7,C CB 79 + BIT 7,D CB 7A + BIT 7,E CB 7B + BIT 7,H CB 7C + BIT 7,L CB 7D + + + Nou, nou!! Dat dat een flink stuk typen was mag wel duide- + lijk zijn. Och mensen wat een klus. Maar goed, dat was het + waar, want dergelijke tabelletjes kunnen wel degelijk heel + handig zijn. Gelukkig maar dat een print optie in de FD zit + want overschijven zou een flinke klus zijn... Tenzij je na- + tuurlijk Patrick heet en flink getrainde armen hebt... + + Maar goed, dit besluit dus de bit-cursus. De volgende keer + gaan we vast wel verder met iets, maar waar over?? + + +Tobias Keizer diff --git a/future_disk/33/pascal_3.md b/future_disk/33/pascal_3.md new file mode 100644 index 0000000..8258825 --- /dev/null +++ b/future_disk/33/pascal_3.md @@ -0,0 +1,150 @@ +Dit is een poging om de langste scroll regel ooit op de FutureDisk te maken (NvdR: dat is mislukt Jeroen, ik heb hem afgekapt!) + + PASCAL (3) + + + ���� Welcome to the third PASCAL course. Ofwel, hallo, dit + ���� is de derde PASCAL cursus op de FD. Het mag dan wel + ���� FutureDisk 33 zijn, maar aangezien de PASCAL cursus pas + ���� zijn derde nummer ingaat zou alles dus helemaal okie + dokie moeten zijn. Wat een gezeur h�! Ik zal maar be- + ginnen, voor ik nog meer onzin uitkraam. + + Vorige keer heb ik het over Koen gehad (helemaal in het begin) + en ja hoor, hij had weer iets te zeiken, dus nu even mijn + antwoord: "Ja Koen, je kunt ook 100 minuten bandjes door mijn + programma laten uitrekenen.". Zo, dat is ook weer opgelost. + (NvdR: ja stomme ezel, dat had ik ook al door!) + + Nu even echt serieus. Deze keer ga ik lussen bespreken. In + PASCAL zijn drie soorten lussen: FOR-TO-DO, REPEAT-UNTIL en + WHILE-DO. Uit de namen kan al ��n en ander afgeleid worden. + Maar ik zal de verschillende lussen met een voorbeeld + behandelen. + + Stel ik wil de getallen 1 t/m 10 op het scherm toveren. Hoe + doe ik dat? Hier komen de drie mogelijkheden: + +FOR-TO-DO: + + PROGRAM ForNext (input,output); + + VAR + teller : integer; + + BEGIN + FOR teller := 1 TO 10 DO + writeln(teller); + END. + +REPEAT-UNTIL: + + PROGRAM RepeatUntil (input,output); + + VAR + teller : integer; + + BEGIN + teller := 0; + REPEAT + teller := teller + 1; + writeln(teller); + UNTIL teller = 10 + END. + +WHILE-DO: + + PROGRAM WhileDo (input,output); + + VAR + teller : integer; + + BEGIN + teller := 0; + WHILE teller < 10 DO + BEGIN + teller := teller + 1; + writeln(teller); + END; + END. + + Dat waren ze. Maar nu de uitleg. In het eerste voorbeeld + (FOR-TO-DO) zie je, dat de variabele "teller" van 1 t/m 10 zal + lopen. Er staat tenslotte dat de teller zal lopen van 1 tot en + met 10, en zolang moet je teller afdrukken. Een FOR lus kan + niet worden onderbroken (voor de echte crack wel, maar dat is + met een GOTO en dat is weer niet gestructureerd en dus niet + netjes). Een FOR lus loopt altijd van onder- tot bovengrens. + Nu denk je natuurlijk: Ik wil ook van 10 naar 1 kunnen lopen, + dat kan, maar dan moet je DOWNTO in plaats van TO gebruiken. + Voor de goede orde: Als de ondergrens groter is dan de + bovengrens (FOR teller := 2 TO 1 DO) dan gebeurt er dus + niets. + + Het tweede voorbeeld (REPEAT-UNTIL) werkt heel anders. Hier + wordt de lus op een bepaalde conditie verlaten. In het + voorbeeld staat dan ook HERHAAL ... TOTDAT teller=10. Zolang + teller niet 10 is, gaat de lus door. Probeer maar eens wat er + gebeurt als je de regel "teller := teller + 1;" weglaat. Je + zult zien dat de lus eindeloos doorgaat; teller wordt ook + nooit 10. + + Het verschil met het tweede en derde voorbeeld is eigenlijk + minimaal. Ook hier wordt de lus verlaten bij een bepaalde + conditie (teller=10), alleen wordt hier eerst gecontroleerd en + daarna pas beslist of de lus doorlopen moet worden. Het grote + verschil is dan ook dat de REPEAT-UNTIL minimaal 1 maal + doorlopen wordt, terwijl dat bij de WHILE-DO niet het geval + is. + + Zo, dat was een snel overzicht van de lus functies in PASCAL. + En nu maar oefenen. Tja, ik kan het niet vaak genoeg zeggen, + veel oefenen, anders leer je het niet. Ik zal, hoewel vorige + keer niemand een reactie heeft gegeven(gek h�) (NvdR: ligt + gewoon aan jou!), ook deze keer wat opdrachten geven. + + OPDRACHTEN: + (1) Maak een programma dat alle mogelijke combinaties van 4 + (hoofd)letters op het scherm zet (doe dit met alleen + FOR-TO-DO, REPEAT-UNTIL of WHILE-DO lussen). + (2) Maak een programma dat alle priemgetallen tot een + ingegeven getal berekend (doe ook dit met alleen + FOR-TO-DO, REPEAT-UNTIL of WHILE-DO lussen). + + Voordat jullie kunnen beginnen moet ik nog even snel wat + uitleggen over compound-statements. In PASCAL is het namelijk + zo, dat na bepaalde opdrachten (FOR-TO-DO, WHILE-DO, + IF-THEN-ELSE) maar ��n opdracht mag staan. Bij de FOR-TO-DO + lus mag dus niet staan: + + WHILE teller < 10 DO + write(teller); + teller := teller + 1; + + De opdracht "write(teller)" is namelijk 1 opdracht en de + volgende opdracht "teller := teller + 1" zou pas worden + uitgevoerd als de WHILE-DO lus voorbij is (nooit(!)). Vaak is + het echter noodzakelijk dat meerdere opdrachten in een lus + worden uitgevoerd. De oplossing hiervoor is het compound- + statement. Een compound-statement is een heleboel statements + omgeven door een BEGIN en een END. Het voorbeeld zal dus + worden: + + WHILE teller < 10 DO + BEGIN + write(teller); + teller := teller + 1; + END; + + Bij het bovenstaande programma zal alles wel naar wens + verlopen. Samenvattend komt het er op neer dat als je bij + lussen (REPEAT-UNTIL is hier de bevestigende uitzondering) + meerdere statements wil laten uitvoeren, dat je die statements + moet laten voorafgaan door BEGIN en eindigen met END. + + Zo, met bovenstaande informatie moet je in staat zijn om de + zes opdrachten te maken. + + Veel plezier, + + Jeroen "In de herhaling" Smael diff --git a/future_disk/33/pascal_4.md b/future_disk/33/pascal_4.md new file mode 100644 index 0000000..5dbe2e0 --- /dev/null +++ b/future_disk/33/pascal_4.md @@ -0,0 +1,148 @@ +Dit is deel vier van de zeer interessante PASCAL cursus... + PASCAL (4) + + + ���� Programmeren is masochisme, maar wat is het lekker + ���� (NvdR:??). Nou ja, als je aan het programmeren BENT + ���� niet, maar als het werkt en die kl*t* machine doet + ���� eindelijk precies wat JIJ wilt, dat is pas een + hoogtepunt. Waarom vertel ik dit allemaal? Als eerste + omdat ik een reactie van Koen wil uitlokken (h� etter, waar + ben je) (NvdR: hiero!) en als tweede een meer belangrijke + reden (Koen is tenslotte niet belangrijk) (NvdR: moet je + iemand horen!) om je te stimuleren om toch vooral door te + gaan, want uiteindelijk lukt het wel! (dat MSX'je kan veel + meer dan je denkt). + + Deze vierde aflevering van mijn PASCAL cursus is gewijd aan + PROCEDURE's en FUNCTION's. In elke programmeertaal ontstaat op + een bepaald moment behoefte aan funkties en procedures. + Waarom? Nou, gewoon, omdat je geen zin hebt om een bepaald + stuk code dat je vaker nodig hebt (bijvoorbeeld een invoer + routine) ook vaker in te tikken. Als je het geheel ��n keer + hebt ingetikt, dan wil je het vaker gebruiken, niet alleen + omdat je maar ��n keer wil tikken, maar ook omdat dat stuk het + doet en je bij overtikken fouten kunt maken. + Wat is nu het verschil tussen FUNCTION en PROCEDURE? Het + verschil zit 'm in de uitkomst. FUNCTION heeft een uitkomst, + PROCEDURE niet. Een heel eenvoudige FUNCTION ziet er als volgt + uit: + + FUNCTION Optel(Getal1:integer;Getal2:integer):integer; + BEGIN (* Optel *) + Optel := Getal1 + Getal2; + END; (* Optel *) + + Bovenstaande funktie is dus niets. Je zou hem nooit gebruiken + in een programma, omdat optellen al standaard aanwezig is. Wel + zou je een funktie schrijven om machten te berekenen, omdat + dat niet standaard in PASCAL aanwezig is. Het voorbeeld geeft + wel duidelijk de struktuur van een funktie weer. + Als eerste staat het gereserveerde woord FUNCTION, waarna de + naam van de funktie volgt (let op; gebruik hiervoor geen + gereserveerde woorden!). Tussen haakjes volgen de variabelen + die je nodig denkt te hebben in de funktie tesamen met hun + type (dit stuk is niet verplicht, omdat je niet altijd + variabelen nodig hebt, denk hierbij aan een random funktie). + Als laatste volgt er nog het type van de uitkomst van de + funktie. + + Na deze eerste regel volgt de body van de functie, die + overigens precies gelijk is aan de body van een programma + (ook hier kun je variabelen declareren en andere funkties of + procedures maken). In het code gedeelte is slechts een ding + verplicht en dat is het toekennen van een waarde aan de + funktie (in het voorbeeld "Optel := Getal1 + Getal2"). Doe + je dit niet, dan krijg je gegarandeerd een foutmelding. + Een klasieke fout is overigens het volgende: + + Optel := 0; + FOR Teller := 1 TO 10 DO + Optel := Optel + Getal[Teller]; + + Hiermee zou je een ARRAY kunnen optellen (denk je), maar het + is verboden om de naam van de funktie (Optel) rechts van het + toekenningsteken te plaatsen en dus werkt het niet. Om het wel + aan de praat te krijgen zul je een variabele "Som" moeten + declareren en het volgende moeten doen: + + Som := 0; + FOR Teller := 1 TO 10 DO + Som := Som + Getal[Teller]; + Optel := Som; + + Zo, nu is de uitleg van een procedure een makkie (dus niet). + Eerst een voorbeeld: + + PROCEDURE Uitkomst(Getal:integer); + + BEGIN (* Uitkomst *) + Writeln('De uitkomst is : ',Uitkomst); + END; (* Uitkomst *) + + Alweer zo'n gemakkelijk voorbeeldje (anders begint Koen te + klagen dat 'ie 't nie begrijp, eikel!)(NvdR: leer jij maar + eens een tekstroutine programmeren!). Je ziet dat de struktuur + nagenoeg gelijk is. + Een procedure heeft geen uitkomst en dat blijkt uit de eerste + regel (heading). Verder mag de procedure geen waarde krijgen + (Uitkomst := 10 is dus uit den boze). Voor de rest is alles + gelijk (er mogen dus ook variabelen gedeclareerd en funkties + of procedures gemaakt worden). + + Je weet nu bijna alles van funkties en procedures, ik moet + alleen nog parameter variabelen uitleggen. Bij een funktie of + procedure geef je gewoonlijk ��n of meer variabelen mee, + alleen, je geeft ze niet mee, je copieert ze. Wat ik bedoel + is, dat de waarde die een variable bezit bij aanroep van de + funktie of procedure, wordt gecopieerd. Aanchouw het volgende + voorbeeld: + + FUNCTION T1(Getal1:integer;Getal2:integer):integer; + + BEGIN (* T1 *) + T1 := Getal1 + Getal2; + Getal1 := Getal1 * 2; + END; (* T1 *) + + En vervolgens in het hoofdprogramma de volgende opdrachten: + + A := 10; + B := 20; + Iets := T1(A,B); + + Deze funktie heeft value parameters, wat betekent dat bij de + aanroep wordt gekeken wat de waarde van de formele parameters + (A en B) is en die gecopieerd wordt naar de actuele parameters + (Getal1 en Getal2). De uitkomst is (hoe kan het anders) 30. De + vraag is echter, wat wordt A? In dit geval veranderd A NIET (A + blijft 10). De copie (Getal1) verandert, maar de formele + parameter (A) blijft gelijk, er bestaat geen link. Daarom + noemt men dit value parameters ofwel waarde parameters, alleen + de waarde wordt doorgegeven. + De andere variabelen zijn parameter variabelen. Een funktie of + procedure met parameter variabelen ziet er als volgt uit: + + FUNCTION T2(VAR Getal1:integer;Getal2:integer):integer; + + BEGIN (* T2 *) + T2 := Getal1 + Getal2; + Getal1 := Getal1 * 2; + END (* T2 *) + + Herhalen we nu de aanroep, dan veranderd A wel in 20. A wordt + nu namelijk als referentie meegegeven. Alle bewerkingen op + Getal2 vinden nu rechtstreeks plaats op A. + + Zo, dat was alles wat ik over funkties en procedures kwijt + wilde. Als oefening deze keer kun je alle voorgaande + oefeningen opnieuw doen, alleen met dit verschil dat je in + het hoofdprogramma alleen maar aanroepen doet naar funkties + of procedures. Oh ja, natuurlijk niet maar een procedure + waarin het hele hoofdprogramma gecopieerd wordt (dan heeft + het oefenen nog geen nut). Oefen trouwens ook lekker veel + met het verschil tussen parameter en value parameters. + + Groetjes, + + Jeroen := Function( Smael ) diff --git a/Future Disk/34/Mathpack.md b/future_disk/34/Mathpack.md similarity index 100% rename from Future Disk/34/Mathpack.md rename to future_disk/34/Mathpack.md diff --git a/future_disk/34/advanced_basic_4.md b/future_disk/34/advanced_basic_4.md new file mode 100644 index 0000000..8216684 --- /dev/null +++ b/future_disk/34/advanced_basic_4.md @@ -0,0 +1,150 @@ +Jaja, we gaan weer verder met de cursi... + ADVANCED BASIC CURSUS 4 + + + Welkom bij het vierde deel van deze cursus. In het eerste + deel van deze cursus zei ik dat er ongeveer 4 delen zouden + zijn, maar dat is niet zo. Na dit deel komen er nog twee + delen, eentje over data-verplaatsingen en eentje over + hybride programmeren met Advanced BASIC. + + + KARAKTERS + + In normaal BASIC is het niet mogelijk om makkelijk een + nieuwe karakter te maken. Advanced BASIC heeft hier een + speciaal commando voor, namelijk _CHAR. Het eerste parameter + geeft het karakter aan dat verandert moet worden en de + volgende 8 parameters geven de vorm van het karakter aan. + Een voorbeeld: + + 10 SCREEN 0:WIDTH 80 + 20 _CHAR(65,128,64,32,16,8,4,2,1) + 30 PRINT STRING$(80,65) + RUN + + Dit programmaatje verandert de letter 'A' (ascii-code is 65). + + + SNELLE COPY + + Advanced BASIC heeft een commando om snel een stuk van het + scherm te kunnen copi�ren, namelijk: + _COPY(sx,sy,sp,nx,ny,dx,dy,dp,[log_op]) + + De parameters sx en sy geven de x- en y-co�rdinaten weer + vanaf waar er gecopi�erd moet worden, sp is de bronpagina, + nx en ny geven aan hoeveel pixels er gecopi�erd moeten + worden, dx en dy zijn de bestemmingsco�rdinaten en dp is de + bestemmingspagina. Het parameter log_op geeft de logische + operatie aan, maar deze mag worden weggelaten. Een + voorbeeld: + + 10 SCREEN 5 + 20 CIRCLE (50,50),50,15 + 30 COPY (0,0,0,100,100,110,110,0) + 40 A$=INPUT$(1) + RUN + + Dit programaatje tekent een cirkel en copi�ert het naar + (110,110). + + Als je logische operatoren wilt gebruiken, moet je dat + anders doen dan in gewoon BASIC. Bij Advanced BASIC moet je + namelijk getallen gebruiken. Hier komt een lijstje welk + getal welk effect heeft: + + Getal Logical operatie + 0 - + 1 AND + 2 OR + 3 XOR + 4 NOT + 8 TIMP + 9 TAND + 10 TOR + 11 TXOR + 12 TNOT + + + MEER LIJNEN + + Een MSX2 (en hoger) kan 26,5 lijnen op scherm 0 en 1 laten + zien, maar MSX-BASIC gebruikt dit niet. Met Advanced BASIC + it het mogelijk om meer lijnen te gebruiken met het commando + _LINES(x). Het aantal lijnen kan alleen 24 en 26 zijn. + Jammer genoeg werkt de BASIC-editor niet goed in de laatste + lijnen. Hier is een voorbeeld: + + 10 SCREEN 0:_LINES(26):KEY OFF + 20 FOR A=0 TO 25 + 30 PRINT "Yippie, 26 lijnen op het scherm!" + 40 NEXT A + RUN + + Het resultaat is 26 keer de tekst van regel 30 op het + scherm. + + + LIJNTJES BEWERKEN + + Advanced BASIC heeft een aantal commando's om lijnen te + verwijderen, toevoegen en een gedeelte van een lijn te + wissen. Lijnen tussenvoegen kan met _INSLINE(y). Y geeft aan + op welke regel een nieuwe lijn moet komen. De lijnen eronder + zullen ��n regel omlaag scrollen en een lege lijn komt op + het scherm. Een voorbeeld: + + 10 SCREEN 0 + 20 PRINT "Dit is een tekstje" + 30 FOR A=0 TO 23 + 40 _INSLINE(0) + 50 NEXT A + RUN + + Dit programma heeft als resultaat een tekstje dat omlaag + scrollt (scrolled?). + + Met _DELLINE(y) is het mogelijk om een lijn te wissen. De + lijnen onder lijn y zullen omlaag scrollen. Met + _DELREST(x,y) is het mogelijk om een deel van een lijn te + wissen, en wel vanaf positie x,y. Een voorbeeld: + + 10 SCREEN 0 + 20 PRINT "Dit is een verdwijnende tekst" + 30 FOR A=31 TO 0 STEP -1 + 40 _DELREST(A,0) + 50 NEXT + RUN + + Het resultaat is een lijn dat letter voor letter verdwijnt. + + + HET RESTJE + + Het is mogelijk om met Advanced BASIC het scherm aan of uit + te zetten. Dit is ook mogelijk onder gewoon BASIC, maar met + Advanced BASIC is het toch eventjes iets makkelijker. _SCRON + zet het scherm aan en _SCROFF zet het scherm uit. + + Als je iets in een window print en het past er niet meer in, + dan scrollt de inhoud van het window omhoog. Dit zal echter + niet altijd gewenst zijn. Daarom is er een commando _SCROLLOFF + dat het scrollen uitzet. Natuurlijk is er dan ook een commando + dat het scrollen weer aan zet, en dat is _SCROLLON. + + Op een Turbo-R is het mogelijk om van processor te wissen. + Dit kan gedaan worden met _SPEED(x). Hier is een lijstje met + mogelijkheden: + + 0 = Z80 + 1 = R800 ROM + 2 = R800 DRAM + anders = fout + + _SPEED werkt ook op een MSX2(+), maar dan kan je alleen de + Z80-mode gebruiken. + + Nou, dit was het dan voor deze keer! + +Arjan Bakker diff --git a/future_disk/34/assembly_cursus_3.md b/future_disk/34/assembly_cursus_3.md new file mode 100644 index 0000000..095ba97 --- /dev/null +++ b/future_disk/34/assembly_cursus_3.md @@ -0,0 +1,186 @@ +De assembly cursus gaat verder... + ASSEMBLY DEEL 3 + + + Welkom, welkom. Welkom bij het derde deel van deze cursus + assembly. Dit maal komen er 2 routine's aan bod, namelijk + een 8bits maal 16bits routine en een snelle copy routine om + het beeld snel op te bouwen. + + + VERMENIGVULDIGEN + + JW schreef op FD 31 dat hij een uur nodig had om een 8bits + maal 16bits routine te perfectioneren. Da's niet echt nodig, + je moet gewoon een 16bits routine pakken en je sloopt er wat + commando's uit en het werkt. + + + DE ROUTINE + + ; 8bits maal 16bits + ; In: A, DE: te vermenigvuldigen waarden + ; Uit: HL: resultaat + + MULUW: LD HL,0 + + MULUW1: RRA + JR NC,MULUW2 + ADD HL,DE + MULUW2: OR A + RET Z + SLA E + RL D + JP MULUW1 + + + UITLEG + + Ok�, de uitleg stond al op FD 30, dus komt 'ie hier niet + meer, op de veranderingen na natuurlijk. Allereerst de + registers. De accu en DE zijn het makkelijkst om te + gebruiken als input. De accu omdat je daarin snel waardes + kunt laden en DE omdat in HL het resultaat komt en het + handig is om BC te kunnen gebruiken als lusteller zonder de + stack te gebruiken. De 16bits optelinstructie ADD werkt + alleen met HL, dus moet het resultaat wel in HL komen. + + Toch even een korte uitleg. RRA schuift A 1 bit naar rechts. + Als carry gezet is, moet DE bij HL opgeteld worden. Dan + wordt er gecontroleerd of A al 0 is. Als dat zo is, is de + routine klaar. Is dat niet zo, dan wordt DE met 2 + vermenigvuldigt en begint de routine overnieuw. + + Als je de routine niet snapt, lees dan FD 30 even en als het + goed is snap je het dan wel (anders ben je een domme aap). + + + SNELLE COPY ROUTINE + + Stel, je wilt snel een screen 5 scherm opbouwen. Da's niet + moeilijk. Stel, je routine is te traag. Dat kan gebeuren. + Dan is hier de oplossing voor je probleem, namelijk een + snelle copy-routine. + + Laten we voor het gemak ervan uitgaan dat je patterns van + 8*8 gebruikt en dat je voor elke pattern 1 byte gebruikt. + Omdat er maar 32 tekens op ��n rij kunnen, heb je maar 5 + bits nodig om aan te geven welk teken van een rij je nodig + hebt. Er blijven dan 3 bits over die aangeven welke rij je + gebruikt. Je kunt de X-positie dan uitrekenen met: + + AND 31 + ADD A,A ; Met 8 vermenigvuldigen + ADD A,A ; (32*8=255) + ADD A,A + + En de Y-positie kun je uitrekenen met: + + AND 224 + SRL A ; Door 4 delen (32/4=8) + SRL A + + Het omrekenen van een byte naar coordinaten gaat dus als + volgt: + + MOVPAT: LD A,(HL) ; Lees byte + + AND 31 ; 32 patterns per rij. + ADD A,A ; Bereken X + ADD A,A + ADD A,A ; A = A * 8 + + LD (SX),A ; Sla X op + + LD A,(HL) ; Lees byte weer + + AND 224 ; 8 rijen + RRA ; Bereken Y + RRA ; Door 4 delen + + LD (SY),A ; Sla Y op + + Vervolgens moet de pattern geprint worden. + + PUSH HL + CALL WAITVDP ; Wacht op VDP + CALL COPY ; Kopi�er pattern + POP HL + + LD A,(DX) ; Pas bestemming X aan + ADD A,8 + LD (DX),A + + JR NZ,MOVPAT1 + + LD A,(DY) ; Pas bestemming Y aan + ADD A,8 + LD (DY),A + + MOVPAT1: + INC HL ; Pas pointer aan + + Zo, da's heel wat. Deze routine past ook automatisch de + pointer naar de screendata aan en ook de bestemmings- + co�rdinaten worden aangepast. Bouw er een lusje omheen en je + scherm wordt snel opgebouwd. Gebruik eventueel geen CALL + WAITVDP en CALL COPY, maar prop die routine's gewoon in deze + routine. Voor de zekerheid komen hier nog even de routines + WAITVDP en COPY. + + + WAT EXTRA ROUTINES + + WAITVDP: ; Wacht totdat VDP klaar is + LD A,2 + OUT (#99),A + LD A,#8F + OUT (#99),A + IN A,(#99) + EX AF,AF + XOR A + OUT (#99),A + LD A,128+15 + OUT (#99),A + EX AF,AF + RRA + JR C,WAITVDP + RET + + COPY: LD A,32 ; Register 32 + OUT (#99),A + LD A,17+128 ; Auto-increment + OUT (#99),A + LD C,#9B + LD B,15 + LD HL,SX + OTIR ; Pomp bytes naar + RET ; register + + SX: DEFB 0,0 + SY: DEFB 0 + P1: DEFB 0 + DX: DEFB 0,0 + DY: DEFB 0 + P2: DEFB 0 + NX: DEFB 8,0 + NY: DEFB 8,0 + REST: DEFB 0,0 + COMMAN: DEFB #D0 + + + TOT SLOT + + Eventueel kun je in plaats van ��n OTIR 15 OUTI's gebruiken, + want dat is weer ietsje sneller. LD B,15 kan dan komen te + vervallen. Verder geldt: Hoe groter de patterns, des te + sneller de routine. + + Als je nog idee�n hebt voor een onderwerp, stuur het dan op + naar de FD en misschien komt er dan wel een tekstje over dat + onderwerp. + + De sources staan ook op disk onder de naam MULUW.ASM en + SCRCOPY.ASM. + +Arjan Bakker diff --git a/future_disk/34/pascal_5.md b/future_disk/34/pascal_5.md new file mode 100644 index 0000000..95d07d1 --- /dev/null +++ b/future_disk/34/pascal_5.md @@ -0,0 +1,333 @@ +Hier volgt alweer deel 5 van mijn PASCAL cursus. Ik hoop dat mensen het leuk vinden dat ik dit doe, anders kan ik beter ophouden. + PASCAL 5 + ======== + + + ���� Alweer deel 5 van deze cursus! Wat gaat de tijd toch + ���� snel(NvdR: snif). Deze keer een kleine cursus, omdat het + ���� over een gemakkelijk onderwerp handelt. Deze cursus + ���� behandelt namelijk het maken van eigen types. + + Bij het declareren van een variabele konden we tot nog toe + alleen maar kiezen uit de standaard type's (integer, real, + boolean, etc.). In PASCAL is het echter ook mogelijk om je + eigen type's te maken en wel als volgt: + + TYPE + OpsomType = {Item1,Item2,Item3}; + SubrangeType = 1..10; + ArrayType = ARRAY[1..10] OF AnderType; + + Je kunt dus een opsommingstype maken bijvoorbeeld: + + DagenVanDeWeek = {Maandag,Dindag,Woensdag,Donderdag,Vrijdag, + Zaterdag,Zondag} + + Of een subrangetype (van elk ander type). Bijvoorbeeld: + + DagenVanDeMaand = 1..31 (* integers dus *) + + Of een ARRAY type. Bijvoorbeeld: + + WekenVanEenJaar = ARRAY[1..52] OF DagenVanDeWeek + + Vervolgens kun je de types gebruiken, maar let wel goed op met + toekenningen e.d. Neem bijvoorbeeld het volgende: + + VAR + Dag : DagenVanDeWeek; + + Dan mag + + Dag := Maandag; + + Maar niet + + Write("Geef dag : "); + Readln(Dag); + + De type's verschillen immers. Bij Readln lees je een integer, + real of string, maar niet een DagenVanDeWeek. + + Wat ook niet kan is + + Dag := Maandag; + Writeln("Het is vandaag ",Dag); + + En wel om dezelde reden als bij Readln. Wat wel kan is + + Dag := Maandag; + CASE Dag OF + Maandag : Write("Maandag"); + Dinsdag : write("Dinsdag"); + . + . + . + + Experimenteer maar eens een beetje met het cre�ren van eigen + type's en je zult zien dat dit heel handig kan zijn. + + Een functie die een beetje met deze type declaratie te maken + heeft is de IN functie. Deze werkt als volgt: + + IF Dag IN {Maandag,Dinsdag,Woensdag,Donderdag,Vrijdag} THEN + writeln("Dit is een werkdag"); + + Je kunt dus met IN kijken of de waarde van een variabele in + een gegeven verzameling zit. Die verzameling moet je wel eerst + opsommen, maar dat is een kleine prijs om te betalen tegenover + (in dit geval) 5 IF statements. + + Zo, dit was kort maar krachtig(NvdR: tja). + + Jeroen "Ik beloof beterschap" Smael + En de Pascal cursus gaat verder... + PASCAL 6 + ======== + + + ���� Tja, vorige keer was ik er niet helemaal met mijn koppie + ���� bij, want ik heb een deel van wat ik moest vertellen + ���� vergeten(NvdR: de eikel!). Ik heb verteld dat je eigen + ���� types kunt maken, maar ��n van de belangrijkste types ben + ik vergeten. Ik ben namelijk het RECORD en de string + vergeten. Hierbij dan ook mijn excuses en de aanvullende + informatie. + + + TYPE + + Over de string kan ik heel snel zijn. De string is een "PACKED + ARRAY[1..?] of char". Een PACKED ARRAY is een array waarvan de + lengte intern wordt bijgehouden. Iets wat bij een string + noodzakelijk is... + + PROGRAM StringVoorbeeld; + + TYPE + Woord = PACKED ARRAY[1..10] OF char; + + VAR + A : Woord; + B : Woord; + + BEGIN (* StringVoorbeeld *) + A:='hallo'; + B:=A; + Writeln(A); + Writeln(B); + END. (* StringVoorbeeld *) + + Het bovenstaande programma lijkt goed (A:=B mag bij arrays, + zolang de arrays van het zelfde type en even groot zijn), maar + er zal twee keer het woord 'hallo' verschijnen, met daarachter + 5 ongewilde karakters (mocht het zo zijn dat het programma + niet al een foutmelding geeft bij de opdracht A:='hallo', + omdat dat niet voldoet aan de voorwaarde van dezelfde grootte). + Bij een PACKED ARRAY zoekt de computer zelf uit hoe groot het + ARRAY is en lost alle genoemde problemen dus op. Bij een + aantal compilers is het mogelijk om een type te gebruiken dat + "string" heet. Genoemd type wordt gebruikt bij TYPE met + "woord = string[10]" of bij VAR met "A : string[10]". + + Dat ik RECORD's vergeten ben is veel erger, omdat daar nou + juist de meeste leuke dingen mee gedaan kunnen worden. Een + klein voorbeeldje: + + + PROGRAM RecordVoorbeeld; + + TYPE + datum = RECORD + dag : 1..31; + maand : 1..12; + jaar : 0..5000; + END; + persoonsgegevens = RECORD + naam : string[30]; (* ik maak + gebruik van + het string + type *) + geboortedatum : datum; + END; + + VAR + persoon : persoonsgegevens; + + BEGIN (* RecordVoorbeeld *) + persoon.naam:='Jeroen Smael'; + persoon.geboortedatum.dag:=27; + persoon.geboortedatum.maand:=10; + persoon.geboortedatum.jaar:=1970; + END. (* RecordVoorbeeld *) + + + Op deze manier kun je dus hele "gegevensbomen" aanleggen. Bij + de persoonsgegevens kun je ook nog het adres, de geboortestad, + etc., etc. toevoegen. Alles wat je maar wilt. Zoals je ziet + moet je wel, om bij de velden te komen een punt gebruiken. + Deze punt is vergelijkbaar met de \ van DOS (het scheidings- + teken van subdirectory's). Tevens zie je dat ik pas jarig ben + geweest, maar dat terzijde(NvdR: inderdaad, dat boeit ons, + ja). + + Met genoemde velden zijn verder natuurlijk wel alle + bewerkingen mogelijk, zo zou de opdracht: + "persoon.geboortejaar:=persoon.geboortejaar+1" een geldige + opdracht zijn. + + Een hele bruikbare "opdracht" bij records is de CASE opdracht. + Deze maakt het mogelijk om ��n of meerdere veldnamen weg te + laten. Met gebruikmaking van de CASE opdracht zou het vorige + (hoofd)programma er als volgt hebben uitgezien: + + BEGIN (* RecordVoorbeeld *) + CASE Persoon OF + naam:='Jeroen Smael'; + geboortedatum.dag:=27; + geboortedatum.maand:=10; + geboortedatum.jaar:=1970; + END; + END. (* RecordVoorbeeld *) + + Hetzelfde (de CASE) kunnen we natuurlijk ook toepassen bij de + geboortedatum en dan ziet het (hoofd)programma er als volgt + uit: + + BEGIN (* RecordVoorbeeld *) + CASE Persoon OF + naam:='Jeroen Smael'; + CASE geboortedatum OF + dag:=27; + maand:=10; + jaar:=1970; + END; + END; + END. (* RecordVoorbeeld *) + + Zoals te zien spaart dit een heleboel tikken. Let er + natuurlijk wel op dat de CASE afgesloten wordt door een END + (anders krijg je een compiler fout). + + + Files + + Het zou uiteraard ook leuk zijn als we met PASCAL toegang + zouden hebben tot de diskette. Gelukkig hebben de makers + daaraan gedacht en kan dat. Voor de beeldvorming zal ik + uitleggen hoe PASCAL een file "ziet". + + Een file is in PASCAL een lange keten gegevens. De gegevens + zitten (en zullen ten eeuwige dagen blijven zitten) in de + volgorde waarin ze zijn weggeschreven. Bij het werken met een + file schuift er een "window" over de file, waardoor altijd + maar ��n gegeven per keer "zichtbaar" is. Het genoemde window + heeft trouwens de onprettige eigenschap dat het alleen maar + vooruit kan schuiven. Ophalen en wegschrijven van waardes + gebeurt via het window. Het window is te bereiken met "File^" + (waar File de naam van de filevariabele is). Ik zal nu wat + opdrachten bespreken die mogelijk zijn met files, waarna nog + een voorbeeld programma volgt. Opdrachten zijn: + + RESET(File) + Opent een file zodat er in gelezen kan worden (zet het + window aan het begin van de file). + REWRITE(File) + Opent de file en maakt hem geschikt om in te schrijven + (file is nu leeg, ook al was hij dat niet!!). + GET(File) + Schuift het window een plaats op (de nieuwe waarde kan met + "Waarde:=File^" opgevraagd worden). + PUT(File) + Zet de waarde van het window in de file en schuift het + window een plaats op (de window waarde kan veranderd worden + met "File^:=Waarde"). + READ(File,Waarde) + Leest uit de file en plaats de gelezen waarde in "Waarde" + (geen geklooi meer met het window, hier gebeurt dat + allemaal automatisch). + READLN(File,Waarde) + Idem als READ, maar leest tevens tot het einde van de regel + (wordt gebruikt bij tekstfiles). + WRITE(File,Waarde) + Schrijft de waarde van "Waarde" in de file en schuift het + window door (ook hier geen geklooi meer met het window). + WRITELN(File,Waarde) + Idem als WRITE, maar plaatst tevens een EOLN (End OF LiNe) + teken in de file (wederom bij tekstfiles). + EOF(File) + Geeft de waarde TRUE als het einde van de file bereikt is + (EOF = End Of File). + EOLN(File) + Geeft de waarde TRUE als het einde van de regel bereikt is + (EOLN = End Of LiNe). + + Offici�el zijn genoemde opdrachten alle opdrachten voor files, + maar de meeste compilers hebben nog twee extra opdrachten, en + dat zijn: + + ASSIGN(File,"FileNaam") + Dit koppelt de "File" aan de "FileNaam". M.a.w. Als ik iets + in de file schrijf, dan komt dit op de schijf in de file + "FileNaam" te staan. Volgens de regels van PASCAL is dit + niet nodig, omdat de fysieke file (de file op schijf) + dezelfde naam krijgt als de variabele "File" heeft. Veel + compilers hebben echter een ASSIGN opdracht nodig, anders + gebeurt er niets (vaak niet eens een foutmelding en al + helemaal geen file). + CLOSE(File) + Dit moge wel duidelijk zijn. Hier wordt de file gesloten. + Deze opdracht zorgt ervoor dat de file ook voor DOS + gesloten wordt, zodat er niet een ge-opende file achter- + blijft als het programma stopt. Deze opdracht moet dus + alleen op het einde van het programma staan. Ook deze + opdracht is geen standaard, maar moet ook bij de meeste + compilers worden toegevoegd voor een goede werking. + + Zo, en dan nu een voorbeeldje: + + PROGRAM FileVoorbeeld; + + TYPE + FileType = FILE OF integer; (* FILE OF AnyType is + mogelijk *) + + VAR + FileVar : FileType; + Teller : integer; + + BEGIN (* FileVoorbeeld *) + ASSIGN(FileVar,"testfile.dat"); (* voor de zekerheid *) + REWRITE(FileVar); (* ik wil er iets + inschrijven *) + FOR Teller:=1 TO 5000 DO + Write(FileVar,Teller); (* dat doe ik hier *) + FOR Teller:=5000 DOWNTO 1 DO + Write(FileVar,Teller); (* en hier ook *) + RESET(FileVar); (* nu wil ik lezen uit + de file *) + WHILE NOT EOF(FileVar) DO + BEGIN + Read(FileVar,Teller); (* hier noem ik + expliciet de file *) + Write(Teller); (* hier niet, dus gaat + de output naar het + standaard uitvoerap- + paraat en dat is het + beeldscherm *) + END; + CLOSE(FileVar); (* voor de zekerheid *) + END. (* FileVoorbeeld *) + + Dit voorbeeld zou een heleboel duidelijk moeten maken. Alles + wat je nu nog moet doen is verder experimenteren. Probeer eens + een tekstfile te lezen en/of schrijven, dan kun je zien wat + EOLN precies doet. + De opdrachten GET en PUT worden weinig gebruikt, maar je kunt + eens kijken hoe ze precies werken (goed voor de beeldvorming). + + Zo, dat was het dan alweer voor deze keer. Groetjes van, + + Jeroen 'ik ben nog lang niet aan mijn EOF' Smael + + C YA @!! diff --git a/future_disk/35/assembly_cursus_4.md b/future_disk/35/assembly_cursus_4.md new file mode 100644 index 0000000..21682d6 --- /dev/null +++ b/future_disk/35/assembly_cursus_4.md @@ -0,0 +1,165 @@ +De assembly cursus gaat verder... + ASSEMBLY (4) + + ���� + ���� + ���� + ���� + + + Het schiet eindelijk een beetje op met deze cursus, maar ja, + deze cursus is ook maar een kwestie van inspiratie. Voor + deze keer heb ik wat routines in elkaar geknutseld om de 2 + extra kleuren van de MSX 2 in screen 0 te kunnen gebruiken. + Ik ga niet vertellen hoe je ze aan moet zetten enzo, want + dat is een kwestie van wat VDP-registertjes vullen. Nee, + deze tekst gaat over hoe snel de kleuren op een bepaalde + positie te zetten of weg te halen. + + Normaal gesproken begint de tabel op adres 2048 in het VRAM. + Deze tabel is 240 bytes groot (=24*80 bits), tenzij je het + aantal lijnen op 26,5 zet, want dan is deze tabel 270 bytes + groot. Vergeet dan ook niet om deze tabel te verplaatsen als + je meer dan 24 regels gebruikt, want de schermtabel + overschrijft dan de kleur-tabel (de schermtabel is dan 2160 + bytes groot). + + Maar goed, ��n byte van de kleurtabel geeft voor 8 plaatsen + aan of ze aan (1) of uit (0) staan. Adres 2048 geeft dus van + coordinaten (0,0) tot (7,0) aan of ze aan of uit staan, + adres 2049 van (8,0) tot (15,0) enz. Een regel gebruikt dan + 10 bytes (=80 bits). Het adres van een coordinaat kun je dan + uitrekenen door de y-coordinaat met 10 te vermenigvuldigen, + de x-coordinaat door 8 te delen, deze 2 optellen en bij 2048 + (het startadres van de tabel) op te tellen. De volgende + routine doet dat: + + ; Bereken adres in kleurtabel + ; In: D: x-coordinaat + : E: y-coordinaat + ; Uit: HL: adres in kleurtabel + + CALCAD: LD HL,2048 ; Start kleurtabel + + LD A,D ; Deel X door 8 + SRL A + SRL A + SRL A + CALL HLA ; en tel bij HL op + + LD A,E ; Vermenigvuldig Y met 10 + ADD A,A + LD B,A + ADD A,A + ADD A,A + ADD A,B + CALL HLA ; en tel bij HL op + RET ; Einde + + De routine HLA doet niets anders dan HL en A bijelkaar op te + tellen en maakt alleen gebruik van de registers A en HL. + Deze routine ziet er als volgt uit: + + HLA: ADD A,L + LD L,A + RET NC + INC H + RET + + Nu kunnen we het adres berekenen van een karakter. Nu moeten + we nog het bitnummer berekenen. De volgende routine doet + dat: + + CALCBT: LD A,D ; Laad x-coordinaat + AND 7 ; laagste 3 bits + LD B,A ; aantal keren schuiven + LD A,128 ; eerste positie is 128 + RET Z ; Positie = 0? Ja -> klaar! + DIVIDE: RRA ; Deel positie door 2 + DJNZ DIVIDE ; Herhalen + RET + + Nu hebben we het bitmasker om een karakter aan te zetten. + Als je een karakter uit wilt zetten, moet je dit masker + inverteren (XOR 255). We kunnen voorts een routine schrijven + die karakters aan en uitzet. Hier komen ze: + + WRTVDP: EQU #47 + WRTVRM: EQU #0177 + RDVRM: EQU #0174 + BIGFIL: EQU #016B + + ; CLS-routine + CLS: LD HL,2048 + LD BC,240 + LD A,0 + JP BIGFIL + + ; Print-routine + ; In: D: X-coordinaat + ; E: Y-coordinaat + ; B: aantal + PUT: PUSH BC + + CALL CALCAD ; Bereken adres + + CALL RDVRM ; Lees oude byte + LD C,A ; Opslaan in C + + CALL CALCBT ; Bereken bitmasker + + OR C ; Originele byte eroverheen + CALL WRTVRM ; Wegschrijven + + INC D ; Pas X aan + LD A,D + CP 80 ; Laatste positie? + JP C,PUT1 ; Nee -> Y niet aanpassen + + LD D,0 ; Pas X en Y aan + INC E + + PUT1: POP BC + DJNZ PUT ; Herhaal routine + RET + + ; Verwijder alternatieve kleuren + ; In: D: X-coordinaat + ; E: Y-coordinaat + ; B: aantal + UNPUT: PUSH BC + + CALL CALCAD ; Bereken adres + + CALL RDVRM ; Lees byte + LD C,A ; Sla het op + + CALL CALCBT ; Bereken bitmasker + + CPL ; Inverteer het + AND C ; Originele masker erover + CALL WRTVRM ; Schrijf byte weg + + INC D ; Pas X aan + LD A,D + CP 80 ; Laatste positie? + JP C,UNPUT1 ; Nee -> Y niet aanpassen + + LD D,0 ; Pas X en Y aan + INC E + + UNPUT1: POP BC + DJNZ UNPUT ; Herhaal routine + RET + + + Deze routines kunnen natuurlijk nog wat aanpassingen + gebruiken, zoals de routines CALCBT en CALCAD direct in de + code te gebruiken, maar voor een cursus moet dat juist niet + omdat het dan een beetje onoverzichtelijker wordt. De + routines zelf spreken voor zich, want er staat genoeg + commentaar bij. Oh ja, de routines staan ook op diskette en + wel in de file ALTCOL.ASM. Tot een volgende keer! + + +Vincent diff --git a/future_disk/35/copy_in_basic.md b/future_disk/35/copy_in_basic.md new file mode 100644 index 0000000..d970a8b --- /dev/null +++ b/future_disk/35/copy_in_basic.md @@ -0,0 +1,82 @@ +Het copy commando in Basic..hmm interessant...hmm ja, daar heb ik nu altijd al eens wat over willen weten...aja, ja ja, ahum, mmmm, ja ja ja interessant...aha hmm ye ye yep ja ja + COPY IN BASIC + + ���� + ���� + ���� + ���� + + + Het COPY-commando heeft meerdere betekenissen. Je kunt er + bestanden mee copi�ren en stukjes van een beeld mee copi�ren. + Dat laatste kan op twee manieren, namelijk van VRAM naar + VRAM en van VRAM naar een array of andersom. De eerste + functie kent iedereen natuurlijk wel, maar de tweede is toch + wel onbekend. Zoals gezegd kun je dus ook een array + gebruiken om naar te copi�ren of weer in het VRAM te zetten. + + Voordat je een stuk scherm naar een array copi�ert, moet je + die eerst berekenen en defini�ren. De grootte van een array + kan met het volgende programmaatje berekend worden: + + 10 PRINT "Bereken grootte voor array-dimensie voor + copy-commando" + 20 PRINT:INPUT "Linker X-coordinaat";X1 + 30 INPUT "Boven y-coordinaat";Y1 + 40 INPUT "Rechter X-coordinaat";X2 + 50 INPUT "Onder y-coordinaat";Y2 + 60 PRINT:INPUT "Schermnummer";S + 70 PRINT:INPUT "Variabele type (% = Integer, ! = Single + precision en # = Double precision";A$ + 80 D=4:IF S=6 THEN D=2 + 90 D=INT((D*(ABS(X2-X1)+1)*(ABS(Y2-Y1)+1)+7)\8)+4 + 100 T=2:IF A$="!" THEN T=4 ELSE IF A$="#" THEN T=8 + 110 D=INT(D/T) + 120 PRINT:PRINT "DIM M(";MID$(STR$(D),2);")" + + Zo, nu komt de COPY-commando zelf aan bod. Eerst de + COPY-commando om een deel van het beeld in het geheugen te + zetten. + + COPY (X1,Y1)-(X2,Y2)[,P] TO V + + X1 is de linker-coordinaat van het te copi�ren gedeelte. Y1 + is de boven-coordinaat van het te copi�ren gedeelte. X2 is + de rechter-coordinaat van het te copi�ren gedeelte. Y2 is de + onder-coordinaat van het te copi�ren gedeelte. P is de + pagina-nummer. V is de naam van de variable waar de tekening + in gezet moet worden. Alleen P hoeft niet ingevuld worden, + zoals te zien is aan de vierkante haken. + + Okee, de tekening moet natuurlijk ook weer op het beeld + kunnen komen. Dit doen we met: + + COPY V[,S] TO (X,Y)[,P[,O]] + + V is weer de naam van de variable waar de tekening in zit. S + is de soort bewerking wat er met de tekening moet gebeuren. + Hierbij is 0 normaal, 1 = horizontaal spiegelen, 2 = + verticaal spiegelen, 3 = 1 + 2. X en Y zijn de coordinaten + waar de tekening heen moet. P is weer de paginanummer en O + is de logische operatie. Aangezien deze tekst niet over + logische operaties gaat, ga ik daar dus ook niet verder op + in. S, P en O mogen weggelaten worden. Hier komt een + voorbeeldprogrammaatje. Start het op en je ziet het effect. + + 10 SCREEN5:DIM M(66):LINE (0,0)-(0,15),15 + 20 LINE (0,7)-(15,7),15 + 30 COPY (0,0)-(15,15) TO M + 40 COPY M,0 TO (100,50) + 50 COPY M,1 TO (100+15,80) + 60 COPY M,2 TO (100,110+15) + 70 COPY M,3 TO (100+15,150) + 80 A$=INPUT$(1) + + Zoals je ziet kun je dus makkelijk effecten gebruiken in + BASIC, maar je moet natuurlijk wel zorgen dat het wel in het + geheugen past, want naar een array copi�ren kost al snel + veel geheugen. Tot de volgende keer... + + +Vincent + diff --git a/Future Disk/35/Datacompressie.md b/future_disk/35/datacompressie.md similarity index 100% rename from Future Disk/35/Datacompressie.md rename to future_disk/35/datacompressie.md diff --git a/future_disk/35/pascal_7.md b/future_disk/35/pascal_7.md new file mode 100644 index 0000000..85739e9 --- /dev/null +++ b/future_disk/35/pascal_7.md @@ -0,0 +1,146 @@ +Jeroenie gaat verder met de Pascal cursus... + PASCAL (7) + + + ���� We zijn bijna aan het einde gekomen van een reeks PASCAL + ���� cursi. Er zijn nog maar twee onderwerpen die ik wil + ���� behandelen: POINTERS en RECURSIE. Pointers is een soort + ���� data-type in PASCAL en recursie is een soort + programmeermethode. Omdat beide onderwerpen interessant + en (mijns inziens) belangrijk voor een programmeur zijn + besteed ik per onderwerp twee teksten hieraan (zodoende kan + ik dus nog drie teksten en FD nummers vooruit). Ik begin dus + met pointers (les 1). + + Wat is het voordeel van een FILE ten opzichte van een ARRAY: + - oneindig (een file kan in principe oneindig lang zijn) + - flexibele grootte (een file kan altijd langer of korter + gemaakt worden) + - weinig geheugen nodig (voor een file is bijna geen + geheugenruimte nodig, wel schijfruimte natuurlijk, maar + daar hebben we tegenwoordig genoeg van) + + Wat is het voordeel van een ARRAY ten opzichte van een FILE: + - snel(1) (ieder element kan onafhankelijk van de andere + opgevraagd worden, dus niet eerst de hele file de revue + laten passeren voordat het laatste element gebruikt kan + worden) +- snel(2) (alles staat in het geheugen en geheugen is v��l + sneller dan disk) +- gemakkelijk (makkelijk te programmeren, denk maar eens aan + een sorteer-algoritme voor files) + + Door genoemde voordelen te combineren zou men een super + gemakkelijk en snel data-type moeten kunnen krijgen. Men heeft + lang (eigenlijk niet, maar voor het verhaal staat dat wel + leuk) gedacht en is met pointers gekomen. Het had snel en + gemakkelijk moeten zijn. Het is snel, maar zeker NIET + gemakkelijk. Wat zijn pointers dan wel vraag je je af? + - snel (alles staat in het geheugen) + - oneindig (zolang er geheugen is kunnen er pointers + aangemaakt worden) +- flexibele grootte (tijdens programma executie kunnen nieuwe + pointers aangemaakt worden) + + Je kunt je nu natuurlijk nog niets bij pointers voorstellen, + maar dat ga ik even veranderen. Wat is een pointer namelijk in + de computer (hoe werkt het)? Een pointer is (zoals de naam al + zegt) een wijzer (NvdR: grote meid!). Genoemde wijzer kan + wijzen naar niets of naar een data-element. Wijst het naar + niets, dan wijst hij naar NIL (gereserveerd woord), dat + (waarschijnlijk) het getal 0 is en dus geheugenruimte 0 is. + Wijst het naar een data-element dan is de pointer het adres + waar dat data-element gevonden kan worden. Dus als ik een + pointer A heb, dan kan de inhoud van A NIL zijn of + (bijvoorbeeld) #a084. NIL wil zeggen dat de pointer nergens + naar wijst, en #a084 dat de pointer naar adres #a084 wijst. + Staat op adres #a084 het getal 10, dan wijst de pointer dus + het getal 10 aan. Grafisch wordt een en ander vaak als volgt + weergegeven: + + A + +-+ +----+ + | |--->| 10 | + +-+ +----+ + + Bovenstaand geval is als een pointer een byte (1 byte in het + geheugen) aanwijst. Er zijn dus wel 3 bytes nodig om een en + ander goed te laten werken (2 voor de pointer (16 bits adres) + en 1 voor het data-element (byte)). Een pointer kan elk data- + type aanwijzen dat de gebruiker maakt, hierdoor is het + mogelijk om een zogenoemde gelinkte lijst te maken (een + pointer die naar een pointer wijst die naar een pointer wijst + die naar een pointer wijst die naar een pointer wijst die naar + een pointer wijst die naar een pointer wijst die naar een + pointer wijst die naar een pointer wijst die naar een pointer + wijst ...............). Op zich heb je daar dus niets aan, + maar als je alle pointers nu eens naar een RECORD laat wijzen + dat een data-element EN een pointer bevat, dan kom je al een + heel eind. Grafisch ziet dat er als volgt uit: + + Hoofd + +-+ +---+-+ +---+-+ +---+-+ +---+-+ +---+-----+ + | |--->| 5 | |--->| 9 | |--->| 4 | |--->| 0 | |--->| 1 | NIL | + +-+ +---+-+ +---+-+ +---+-+ +---+-+ +---+-----+ + + Allemaal heel leuk, maar hoe gebruik je dit (oftewel geef een + programma, dan zien we tenminste iets). Kijk maar eens naar de + file "PASCAL7.PAS" op deze diskette, daar staat een voorbeeld + in. + + Bij TYPE staat de declaratie van een pointer: + typenaam1 = ^typenaam2 (* ^ staat voor 'pointer naar' *) + + Hier is dus wel iets geks aan de hand, want Next is een + pointer naar Element, maar Element is nog niet bekent...... + MAG DAT???? Ja, dat mag, als uitzondering. Zouden we Element + en Point in de declaratie omdraaien, dan zouden we namelijk een + soortgelijk probleem hebben omdat in Element, Next van het + type Point is. Bij pointers mag er dus een type vooruit genoemd + worden. Overigens wel in de volgorde zoals in het voorbeeld + staat (dus eerst het pointer-type en daarna pas het type waar + de pointer naar wijst). + + De variabele declaratie zal geen problemen opleveren, dit in + tegenstelling tot het hoofdprogramma. Het eerste nieuwe dat we + tegenkomen is 'Main:=NIL'. Aangezien Main nog een + ongedefinieerde waarde heeft, maken we deze eerst gedefinieerd + (vanaf nu wijst Main dus nergens naar). Het volgende is + 'NEW(Temp)'. Hier wordt een geheugenplaats aangevraagd voor + het data-type van Temp. (voor de opdracht NEW wijst de pointer + Temp naar een ongedefinieerde plaats in het geheugen. Bij de + NEW opdracht wordt er in het geheugen gezocht naar een plaats + waar het data-type van de pointer inpast (in dit geval een + integer en een pointer)). Deze geheugenruimte wordt dan + gereserveerd voor zulk een data-type en de pointer wijst vanaf + nu naar genoemde plaats in het geheugen). + + De toekenningsopdrachten zijn min of meer vanzelfsprekend als + je weet dat pointer^ het data-element is (dus Main^ is een + RECORD met twee velden (Value en Next), de inhoud van Value + is dus te bereiken met Hoofd^.Value). Wel moet ik vermelden + dat als je een pointer (bijvoorbeeld Temp) zelf veranderd, dat + de computer dan niet de geheugenruimte vrijmaakt waar de + pointer naar wijst. Door alsmaar 'NEW(Temp)' als opdracht te + geven zou het geheugen dus vollopen (zorg ervoor dat je het + adres van het data-element ergens bewaart, anders ben je het + voorgoed KWIJT in het walhalla van je computer geheugen). In + het voorbeeld programma raak ik niets kwijt (ook visueel + zichtbaar) omdat ik een gelinkte lijst maak (ik laat de + elementen naar elkaar wijzen). + + Wil je de geheugenplaats waar een pointer naar wijst vrij + maken dan gebruik je DISPOSE (zoals ook op het einde van het + programma te zien is). + + Zo, dat was het dan alweer. Volgende keer meer, veel meer over + pointers, maar voor nu 2 opdrachten om jezelf te testen: + + (1) Zie voorbeeld programma, maar nu de getallen in volgorde + van invoer in de lijst plaatsen. + (2) Zie voorbeeld programma, maar nu de getallen gesorteerd in + de lijst plaatsen. + + Veel plezier, + +Red XIII diff --git a/future_disk/35/pascal_8.md b/future_disk/35/pascal_8.md new file mode 100644 index 0000000..2294813 --- /dev/null +++ b/future_disk/35/pascal_8.md @@ -0,0 +1,381 @@ +Jeroen programmeert verder en verder en kan het nog steeds niet... + PASCAL (8) + + + ���� Hallie hallo, hier is Smael weer met zijn PASCAL cursus. + ���� Deel 8 deze keer (nog twee en dan is het alweer + ���� voorbij). In deel 8 gaan we dieper in op pointers. + ���� Vorige keer heb ik uitgelegd wat pointers zijn en wat je + ermee kunt. Nu is het dus tijd voor een groot voorbeeld. + Als voorbeeld neem ik een programma om namen en adressen op te + slaan (een soort database dus). Goed, daar gaat 'ie (wat + hebben we weer een plezier)!! (NvdR: ja nou) + + Het programma staat op de disk als 'PASCAL8.PAS'. De listing + vind je terug in deze tekst, maar alleen ter verduidelijking. + + De declaraties veronderstel ik bekend (moet je kunnen) en daar + ga ik dus niet verder op in. Wel staan ze hier even vermeld, + zodat je de rest van het programma begrijpt: + + PROGRAM Pascal8 (Input,Output,Names); + + CONST + Max = 30; + + TYPE + Point = ^Row; + Row = RECORD + Name : String[Max]; + Address : String[Max]; + Next : Point; + END; + + VAR + Names : Text; + Choice : integer; + Main : Point; + Temp : Point; + Number : integer; + + Ik ga dus verder met de eerste procedure, aangezien hier + misschien dingen zijn die je niet begrijpt. Als ik zo naar + deze procedure kijk, dan kom ik tot de ontdekking dat je + alleen het commando 'ClrScr' niet kent, maar dat de naam alles + duidelijk maakt. Let ook op hoe ik het probleem van de + toetsdruk oplos. De computer wacht totdat ik op de + toets heb geramd, daarvoor kun je dus alle letters inrammen + die je wil (ze zullen zelfs zichtbaar zijn op het scherm). + Niet erg netjes dus, maar dat kun JIJ verbeteren (gebruik de + functie 'KeyPressed'). Verder gesneden koek: + + PROCEDURE welcome; + + BEGIN (* welcome *) + clrscr; + writeln('This is an example that comes with FD#35'); + writeln; + writeln('This little programm makes it possible'); + writeln('to create a list of addresses using'); + writeln('pointers.'); + writeln; + writeln; + writeln('Enjoy !!'); + writeln; + writeln; + writeln; + write('Press to continue.'); + readln; + END; (* welcome *) + + Ook deze procedure moet gesneden koek zijn (alleen maar wat + Writeln's en Readln's). Wederom kun je een en ander + verbeteren. Als je namelijk een verkeerde keuze maakt, dan + wordt op de volgende regel opnieuw naar je keuze gevraagd. + Maak je ongeveer 20 keer de verkeerde keuze, dan is het + keuzemenu niet meer te zien (uit het beeld geschoven) en dat + is niet zo netjes. Read it and weep : + + PROCEDURE menu(VAR choise:integer); + + BEGIN (* menu *) + clrscr; + writeln('You can choose from :'); + writeln; + writeln('(1) Load adresses'); + writeln('(2) Insert address'); + writeln('(3) Show adresses'); + writeln('(4) Delete address'); + writeln('(5) Save addresses'); + writeln('(6) Stop'); + writeln; + writeln; + writeln; + choise:=0; + REPEAT + write('Your choice : '); + readln(choise); + UNTIL (choise>=1) AND (choise<=6); + END; (* menu *) + + Hier wordt het interessant. Er wordt een file ingelezen van + namen die ooit al eens zijn ingevoerd. Deze heb ik lekker + gemakkelijk gehouden. Vergelijk hem maar eens met de SAVE + procedure en je komt tot de ontdekking dat de namen omgekeerd + ingelezen worden. Wat bedoel ik? Als de namen in alfabetische + volgorde zijn weggeschreven (als voorbeeld), dan worden ze + anti-alfabetisch (dus net omgekeerd van Z naar A) ingelezen. + Let ook op de VAR (in de procedure-kop) bij Main en Names. + Bij Names is het altijd verplicht (een file kan niet in het + geheugen gekopieerd worden), maar bij Main zou ik het weg + kunnen laten. Of niet (een pointer kan in het geheugen + gekopieerd worden)? In dit geval niet!! + + Als er al ��n naam, of meerdere, ingevoerd waren, dan kon ik + het weglaten (moet de rest wel achteraan toegevoegd worden) + aangezien Main dan niet meer hoeft te veranderen (let vooral + op de voorgaande opmerking). Nu wordt elke nieuwe naam vooraan + in de lijst bijgeschoven en dus veranderd Main bij elke naam. + Conclusie : VAR kan niet weggelaten worden (anders ben je je + namen kwijt als je terugkeert naar het hoofdprogramma). + + Let ook op het gebruik van de EOF functie. Ik hou er rekening + mee dat een file verminkt is. Ik zou kunnen volstaan met de + EOF controle bij de WHILE-lus, maar als de file verminkt is, + dan gaat het fout bij het inlezen van het adres. Gevolg is een + crash van de computer en dus zijn al je gegevens weg. Let + hier op bij het programmeren van een grote toepassing. Let + tevens op de 'Close(Names)' aan het einde van de procedure, + deze is geplaatst om problemen te voorkomen indien je na het + inlezen het programma be�indigd (er staat immers nog een file + open). Verder bekend (neem ik aan) : + +PROCEDURE Loading(VAR Main:Point;VAR Names:Text); + + VAR + Temp : Point; + + BEGIN (* Loading *) + Assign(Names,'address.txt'); + Reset(Names); + WHILE NOT EOF(Names) DO + BEGIN + New(Temp); + IF NOT EOF(Names) THEN + Readln(Names,Temp^.Name) + ELSE + Temp^.Name:=''; + IF NOT EOF(Names) THEN + Readln(Names,Temp^.Address) + ELSE + Temp^.Address:=''; + Temp^.Next:=Main; + Main:=Temp; + END; + Close(Names); + END; (* Loading *) + + Ook deze procedure moet geen echte problemen opleveren (zeker + niet als je de vorige procedure begrepen hebt). Hier worden + namen toegevoegd aan de lijst (wederom vooraan). Ik houd er + rekening mee dat de gebruiker gekke dingen doet, vandaar de + dubbele controle op het invoeren van een lege regel. Let ook + op de twee Dispose opdrachten op het einde van de procedure!! + Again, read it and weep : + +PROCEDURE Adding(VAR Main:Point); + + VAR + Temp : Point; + + BEGIN (* Adding *) + New(Temp); + ClrScr; + Writeln('Adding an address to the list'); + Writeln; + Writeln; + Writeln('Give a name and an address (RETURN is stop).'); + Writeln; + Write('Give name : '); + Readln(Temp^.Name); + IF Temp^.Name<>'' THEN + BEGIN + Write('Give address : '); + Readln(Temp^.Address); + IF Temp^.Address<>'' THEN + BEGIN + Temp^.Next:=Main; + Main:=Temp; + END + ELSE + Dispose(Temp); + END + ELSE + Dispose(Temp); + END; (* Adding *) + + Aan deze procedure maak ik geen woorden vuil (buiten het feit + dat ik je wijs op het handige gebruik van de MOD functie bij + de REPEAT-UNTIL): + +PROCEDURE Print(Main:Point); + + VAR + Counter : integer; + Temp : Point; + + BEGIN + Temp:=Main; + Counter:=0; + REPEAT + ClrScr; + REPEAT + IF Temp<>NIL THEN + BEGIN + Writeln(Temp^.Name); + Writeln(Temp^.Address); + Temp:=Temp^.Next; + END + ELSE + BEGIN + Writeln; + Writeln; + END; + Writeln; + Counter:=Counter+1; + UNTIL (Counter MOD 7)=0; + Write('Press to continue.'); + Readln; + UNTIL Temp=NIL; + END; (* Print *) + + Dit is natuurlijk de meest interessante procedure. Je zou hem + nu echter (na het lezen van Laden en Plus) zo goed als moeten + kunnen dromen. Nee, dat is maar een grapje (NvdR: haha). + Zelfs ik heb moeten denken hoe je dit gemakkelijk en snel + zou kunnen oplossen. Door een truukje gebruik ik maar twee + hulppointers in plaats van drie (ik gebruik de Next van + Temp1 omdat die toch niet wordt gebruikt). Wat bij dit + soort procedures lastig is zijn niet de normale gevallen + (een naam middenin de lijst verwijderen), maar de bijzondere + gevallen (een naam in het begin of een naam op het einde + verwijderen). Probeer dit ook altijd goed uit als je zoiets + maakt, zodat je niet voor verassingen komt te staan. + Enjoy: + +PROCEDURE Min(VAR Main:Point); + + VAR + Temp1 : Point; + Temp2 : Point; + + BEGIN (* Min *) + New(Temp1); + ClrScr; + Writeln('Deleting an address from the list'); + Writeln; + Writeln; + Writeln('Give a name (RETURN is stop)'); + Writeln; + Write('Give name : '); + Readln(Temp1^.Name); + IF Temp1^.Name<>'' THEN + BEGIN + Temp2:=Main; + IF Main^.Name=Temp1^.Name THEN + BEGIN + Main:=Main^.Next; + Dispose(Temp2); + END + ELSE + BEGIN + WHILE Temp2<>NIL DO + IF Temp2^.Name<>Temp1^.Name THEN + BEGIN + Temp1^.Next:=Temp2; + Temp2:=Temp2^.Next; + END + ELSE + BEGIN + Temp1^.Next^.Next:=Temp2^.Next; + Dispose(Temp2); + Temp2:=NIL; + END; + END; + END; + Dispose(Temp1); + END; (* Min *) + + Tja, moet ik dit nog bespreken? Dacht het niet : + +PROCEDURE Saven(Main:Point;VAR Names:Text); + + VAR + Temp : Point; + + BEGIN (* Saven *) + Assign(Names,'adres.txt'); + Temp:=Main; + Rewrite(Names); + WHILE Temp<>NIL DO + BEGIN + Writeln(Names,Temp^.Name); + Writeln(Names,Temp^.Address); + Temp:=Temp^.Next; + END; + Close(Names); + END; (* Saven *) + + Hier wordt natuurlijk alles samengevoegd, maar dat het je al + begrepen: + + BEGIN (* MainProgramm *) + New(Main); + Main:=NIL; + welcome; + REPEAT + menu(choise); + CASE Choice OF + 1 : Loading(Main,Names); + 2 : Adding(Main); + 3 : Print(Main); + 4 : Min(Main); + 5 : Saven(Main,Names); + END; + UNTIL choise=6; + Temp:=Main; + WHILE Main<>NIL DO + BEGIN + Main:=Main^.Next; + Dispose(Temp); + Temp:=Main; + END; + END. (* MainProgramm *) + + Dat was het. Weinig commentaar van mij dit keer, maar dat komt + omdat je dit zelf moet uitzoeken. Het programma werkt (ik heb + het uitvoerig getest) en dus kun je hier kijken hoe het moet. + Wat je moet doen om zelf meer te leren is het programma + aanpassen (daar heb ik het voor gemaakt). Dit programma bevat + alleen maar de namen en adressen (dat adres is niet compleet) + en moet dus eigenlijk uitgebreid worden met postcode, + woonplaats en telefoonnummer. Vandaar de volgende opdrachten: + + (1) Verbeter de invoerroutines, zodat een en ander mooier + uitziet als er een fout wordt gemaakt. + (2) Breid het programma uit, zodat ook de postcode, + woonplaats en het telefoonnummer van de betrokkene + ingevoerd en bewaard kan worden. + (3) Sorteer de gegevens alfabetisch (Tip : maak gebruik van + een bubblesort algoritme, dat is het gemakkelijkst bij + pointers). + + Smael, wat is bubblesort? Bubblesort is een sorteerroutine. + Hoe werkt dat? Als volgt : + (1) X <- 1 + (2) Vergelijk element X en X+1 met elkaar + (3) ALS element X+1 < element X DAN + wissel element X en element X+1 + (4) X <- X+1 + (5) ALS nog elementen DAN + ga naar stap 2 + (6) ALS gewisseld (tijdens ��n doorgang) DAN + ga naar stap 1 + En gesorteerd is die hap. + + Bubblesort werkt dus met doorgangen. Per doorgang zorg je + ervoor dat minimaal 1 element op de goede plaats komt (je + schuift dat element telkens voor je uit). Na ��n doorgang heb + je dus alle elementen minimaal ��n maal bekeken. Zolang je dus + wisselt (al is het maar ��n keer per doorgang) ben je nog niet + klaar met sorteren. Dit lijkt niet effici�nt, maar is het wel + (bubblesort is ongeveer 5 keer sneller dan de ouderwetse + sorteermethode met de twee FOR-NEXT loops) en daarbij is het + ook nog eens het gemakkelijkst bij pointers (hoe wil je dat + met twee FOR-NEXT loops oplossen?). + + Zo, dat was het. Tot de volgende keer, dan gaan we het hebben + over recursie (en dat is pas ECHT leuk). Groetjes, + + +Red XIII diff --git a/future_disk/36/advanced_basic_5.md b/future_disk/36/advanced_basic_5.md new file mode 100644 index 0000000..ecef032 --- /dev/null +++ b/future_disk/36/advanced_basic_5.md @@ -0,0 +1,108 @@ +Arjan bazelt wat over Advanced Basic... + + ADVANCED BASIC (5) + + + Welkom bij alweer het vijfde deel van deze cursus. Deze keer + ga ik het hebben over data-verplaatsingen, zoals ik de + vorige keer beloofd had. + + Het komt nogal eens voor dat je gegevens van ram naar vram + of andersom wilt verplaatsen. In BASIC gaat dit normaal + gesproken nogal traag en daarom heeft ADVANCED BASIC wat + extra commando's daarvoor, namelijk: + + _RAMRAM(startadres,aantal,bestemming) + Verplaatst aantal bytes vanaf startadres naar + bestemming. Een nuttig voorbeeld weet ik niet zo snel te + verzinnen. + + _RAMVRAM(startadres,aantal,bestemming,pagina) + Verplaatst aantal bytes van ram naar vram. Pagina is om + aan te geven of de 1e 64 kB of de 2e 64 kB vram als + bestemming gebruikt moet worden. Een voorbeeld: + 10 SCREEN 0 + 20 A$="Dit is een tekst ":HL=&HA000 + 30 FOR A=1 TO LEN(A$) + 40 POKE HL,ASC(MID$(A$,A,1)):HL=HL+1 + 50 NEXT A + 60 _RAMVRAM(&HA000,LEN(A$),240,0) + RUN + + Dit programmaatje zet een string in het geheugen en + verplaatst het naar adres 240 van het VRAM, wat in SCREEN 0 + de vierde regel is. + + _VRAMRAM(startadres,pagina,aantal,bestemming) + Verplaatst aantal bytes van vram naar ram. Een voorbeeld + lijkt me overbodig. + + _VRAMVRAM(startadres,pagina,aantal,bestemming,pagina) + Verplaatst aantal bytes van vram naar vram. Een leuk + voorbeeldje: + 10 SCREEN 0 + 20 PRINT "Deze tekst scrolled naar links" + 30 _VRAMVRAM(1,0,79,0) + 40 FOR A=1 TO 100:NEXT A + 50 IF STRIG(0)=0 THEN GOTO 30 + RUN + + Dit programmaatje print een tekstje en laat het naar links + scrollen en stopt pas als er op spatie gedrukt word. + + _OUTM(startadres,aantal,poort) + Stuurt aantal bytes vanaf startadres naar een I/O-poort. + Vooral handig bij de nieuwe MSX-uitbreidingen als OPL4 en + GFX9000. + + _INM(poort,aantal,bestemming) + Haalt aantal bytes uit I/O-poort en zet het in ram. Zie ook + _OUTM. + + + WHAT'S NEXT + + Verder heeft Advanced BASIC nog wat commando's om het (v)ram + met een waarde te vullen, namelijk: + + _FILLRAM(startadres,aantal,waarde) + Vult ram met een bepaalde waarde. Een voorbeeld: + 10 _FILLRAM(&H8000,128,0) + 20 PRINT "Deze tekst zie je niet meer...." + RUN + + Het programma wordt helemaal overschreven met nullen. De + tekst in regel 20 zul je dus niet meer te zien krijgen en + het programma stopt gewoon. + + _FILLVRAM(startadres,pagina,aantal,waarde) + Vult vram met een bepaalde waarde. Een voorbeeld: + 10 SCREEN 0 + 20 _FILLVRAM(0,0,24*80,65) + 30 IF STRIG(0)=0 THEN GOTO 30 + 40 CLS + RUN + + Dit programmaatje vult het hele scherm met de letter A. Na + een druk op de spatie kom je weer in BASIC. + + + WAT RESTJES + + Als laatst geef ik nog 2 commando's die niet zoveel met + data-verplaatsingen hebben te maken, namelijk: + + _GETPAL(kleur,rood,groen,blauw) + Leest de RGB-waardes van een kleur en zet die op de adressen + rood, groen en blauw. + + _HOME + Verplaatst de cursor van een window naar positie (0,0). + + De volgende en laatste keer komt hybride-programmeren onder + Advanced BASIC aan bod, waarmee je leuke dingen kunt doen + (onder andere Advanced BASIC combineren met KUN-BASIC!). Tot + dan! + + +Arjan Bakker diff --git a/future_disk/36/assembly_cursus_5.md b/future_disk/36/assembly_cursus_5.md new file mode 100644 index 0000000..c29fd72 --- /dev/null +++ b/future_disk/36/assembly_cursus_5.md @@ -0,0 +1,110 @@ +Arjan programmeert er rustig op los... + + ASSEMBLY (5) + + + Deze keer gaan we het hebben over screensplits, paletsplits + en alle andere soorten splits die je maar kunt bedenken. Een + goed voorbeeld van een screensplit zie je nu terwijl je aan + het lezen bent. Eigenlijk zijn er zelfs 2 screensplits, want + alleen de tekst beweegt en de border staat stil. + + Een split is eigenlijk heel simpel om te maken. Het kan + zelfs op 2 verschillende manieren. Je kunt namelijk de VDP + een interrupt laten genereren als de lijn voorbij is en je + kunt zelf testen of de VDP al voorbij de lijn is. Deze + laatste methode zal ik hier bespreken, de eerste komt een + volgende keer aan bod. + + Zoals gezegd is een split heel simpel. Eerst doe je nog wat + dingetjes totdat je denkt dat de VDP ongeveer is bij de lijn + waar je de split wilt hebben. Dan zet je in register 19 NA + welke lijn je de split wilt hebben. Daarna test je of bit 0 + van statusregister 1 een 1 is. Als dat zo is, is de VDP + klaar met die lijn. Vervolgens selecteer je een andere page, + schermmode, palet of whatever. Dit kost wel wat tijd, dus + zorg ervoor dat de lijnen bij de split dezelfde kleur + hebben want anders gaat die lijn knipperen. + + Een voorbeeldje: stel je wilt de helft van het scherm page 0 + hebben en de andere helft page 1. Dan zet je in register 19 + de waarde 105, dus komt de split bij lijn 106. Lijn 106 maak + je dan op beide pagina's dezelfde kleur en vervolgens test + je of de lijn al voorbij is. Daarna selecteer je page 1 en + dan wacht je weer op een interrupt om page 0 te selecteren. + + De volgende source zal het wel duidelijker maken. De source + staat ook op disk onder de naam SCRSPLIT.GEN. Natuurlijk is + er ook een klein voorbeeldje bij, namelijk SCRSPLIT.BAS, + welke deze routine gebruikt. Dit programmaatje laat ook zien + wat er gebeurt als je de lijnen bij de split niet dezelfde + kleur geeft. + + defb #fe ; BLOAD-header + defw start,einde,start + + org #d000 + + start: ei + halt + + ld a,31 ; 31 = page 0, 63 = page 1 + out (#99),a ; 127 = page 2, 255 = page 3 + ld a,2 + 128 + out (#99),a ; Selecteer page 0 + + xor a + call #d8 + or a + ret nz ; Spatie ingedrukt = stoppen + + ld a,105 ; Lijn voor screensplit + out (#99),a + ld a,19 + 128 + out (#99),a ; Stuur lijn naar register 19 + + ld a,1 + out (#99),a + ld a,15 + 128 + out (#99),a ; Selecteer statusregister 1 + nop + nop ; geef VDP wat tijd + split: in a,(#99) ; lees statusregister 1 + bit 0,A ; test bit 0 (0 = niet + ; voorbij lijn) + jp z,split ; herhaal test indien nodig + + ld a,63 + out (#99),a + ld a,2 + 128 + out (#99),a ; selecteer page 1 + + xor a + out (#99),a + ld a,15 + 128 + out (#99),a ; Selecteer statusregister 0 + + jp start ; herhaal + + einde: + + Een kleine opmerking wil ik nog maken over het selecteren + van statusregister 0. Dit register moet geselecteerd worden, + omdat de BIOS met IN A,(#99) dit register wil lezen terwijl + 'ie dit register meestal niet eerst selecteert (om tijd te + sparen). + + Als je maar ��n split hebt, hoef je register 19 maar ��n + keer te veranderen, zodat je weer (iets) meer tijd hebt voor + andere dingen. Dit heb ik hier niet gedaan voor de duidelijk- + heid. Natuurlijk is het mogelijk om meerdere splits te maken. + Je zet de routine voor de split vaker in je code, maar dan + telkens met een andere lijn. Zo simpel is dat. + + Dit was het dan voor deze keer. De volgende keer zal ik + .LIB-files behandelen (een file waar je alle files in + propt). Dat wordt een lekker lange aflevering, maar dat mag + ook wel eens een keertje, of niet soms? + + +Arjan Bakker diff --git a/future_disk/36/datacompressie_2.md b/future_disk/36/datacompressie_2.md new file mode 100644 index 0000000..24bba27 --- /dev/null +++ b/future_disk/36/datacompressie_2.md @@ -0,0 +1,145 @@ +Data compressie is een heel handig iets. Het zorgt ervoor dat je meer dan drie teksten per FD kan lezen, handig toch? + + DATA-COMPRESSIE (2) + + + De vorige aflevering van deze tekst eindigde met de + opmerking van Koenie dat ik de behandelde theorie iets meer + uit zou moeten werken en guess what: dat doe ik hier dan ook + (de klant is koning). Natuurlijk moet je zelf nog wat + knutselen aan deze routine's, want anders is er ook niets + aan. + + De (de-)cruncher is ontstaan omdat ik bezig was met een + muziekprogramma welke nu al tijden gecanceld is (NvdR: Cool, + heeft het muziekprogramma toch nog iets opgebracht!). + Ongecomprimeerde muziekdata neemt veel ruimte in beslag en + daarom maakte ik een simpele (de-)cruncher, welke 8 bytes + (wow!) kon crunchen. Natuurlijk zorgden de routine's + eromheen ervoor dat alles gecrunched werd, maar de basis was + 8 bytes, omdat er 8 bits in ��n byte zitten. + + Voor diegenen die de vorige deel niet hebben gelezen komt + hier eventjes een korte uitleg. In een file komen bepaalde + bytes vaak voor, zoals bijvoorbeeld in teksten de byte 32 (= + spatie) vaak voorkomt. Door nu voor elke byte met ��n bit + aan te geven of een byte gelijk is aan de byte die het meest + voorkomt, kun je (als het meezit) de files behoorlijk + kleiner maken. Een voorbeeldje: + + De file bestaat uit de volgende 16 bytes: + 0 25 4 0 3 0 0 195 0 5 201 0 0 0 65 32 + + De 0 komt het meest voor (8 keer). Door ��n bit te gebruiken + om aan te geven of een byte 0 is (bit geset) of ongelijk + (bit gereset), kun je de nullen achterwege laten en alleen + de andere bytes bewaren. Gecrunched komt de data er dan zo + uit te zien (de eerste byte van de regel is binair, de rest + is decimaal): + %10010110 25 4 3 195 + %10011100 5 201 65 32 + + De data is nu nog maar 10 bytes lang, een besparing van zo'n + 40%. Natuurlijk moet je de computer ook laten weten wat er + bedoeld wordt als een bit ��n is, dus kost het weer een byte + extra. + + + CRUNCH IT + + Hier volgt de crunch-routine, met achter de code wat + commentaar zodat het mogelijk moet zijn om deze routine te + begrijpen. + + ; Crunch-routine + ; In: HL: adres van ongecomprimeerde data + ; Uit: HL: adres van gecomprimeerde data + ; E: aantal bytes + ; Verandert: AF, BC, DE, HL, IX + crunch: ld ix,crubuf+1 ; adres waar ongecrunchde + ; bytes komen + ld d,0 ; geeft aan welke bytes + ; gecrunched zijn + ld e,1 ; Lengte gecrunchde data + ld b,8 ; 8 bytes te comprimeren + + crunc1: ld a,(hl) ; lees byte + inc hl + or a ; Gelijk aan 0 ? + jp z,crunc2 ; Ja -> crunc2 + ld (ix),a ; Nee -> sla waarde op + inc ix ; verhoog pointer + sla d ; Vul 0 in in statusbyte + inc e ; Verhoog aantal met 1 + djnz crunc1 ; herhalen + ld hl,crubuf + ld (hl),d ; bewaar status + ret ; finished! + + crunc2: sla d ; bits opschuiven + inc d ; Vul 1 in bij status + djnz crunc1 ; herhalen + ld hl,crubuf + ld (hl),d ; bewaar status + ret ; finished! + + crubuf: defs 9 ; Plek waar data komt + + Deze routine gaat er van uit dat de meest voorkomende byte 0 + is. Als je dit wilt aanpassen, moet je na de instructie + 'LD B,8' de instructie 'LD C,x" zetten, waarbij de x staat + voor het getal dat het meest voorkomt. Verder moet je 'OR A' + veranderen in 'CP C' en klaar is je routine. + + + DECRUNCH IT + + Okay, de crunch-routine was niet echt moeilijk h�! Dan volgt + hier nu de decrunch-routine, welke net zo simpel is! + + ; decrunch-routine + ; In: hl: data-string + ; Uit: hl: uitgepakte string + ; Verandert: AF, BC, DE, HL, IX + dcr: ld a,(hl) ; statusbyte + ld ix,dcrbuf ; Plek waar uncrunchde data + ; terecht komt + ld bc,8 * 256 ; 8 bytes (B), vulbyte=0 (C) + inc hl + + dcr1: add a,a ; Hoogste bit naar carry + jp c,dcr2 ; Carry gezet -> dcr2 + ld d,(hl) ; Haal byte uit gecrunchde + ld (ix),d ; data en bewaar het + inc hl ; verhoog pointers + inc ix + djnz dcr1 ; herhaal de zooi + ld hl,dcrbuf + ret ; finished! + + dcr2: ld (ix),c ; vul een nulletje in + inc ix ; Verhoog pointer + djnz dcr1 ; herhalen maar + ld hl,dcrbuf + ret ; finished! + + dcrbuf: defs 9 ; plek waar data komt + + + TOT SLOT + + Deze routine's zijn redelijk snel, zo'n 20kB per seconde is + toch wel te halen. Toch zijn er verbeteringen denkbaar, door + niet groepjes van 8 bytes te gebruiken, maar gewoon van ��n + byte. Je moet dan eerst ��n bit wegschrijven om aan te geven + of de data gecrunched is (1) of niet (0) en als de data niet + gecrunched is, bewaar je de te crunchen byte en kun je dit + herhalen. Dit is wel iets lastiger, omdat je dan met + bitstreams moet gaan werken. Het heeft dan wel als voordeel + dat de gecrunchte files iets kleiner worden, maar veel maakt + dat ook niet uit. + + De source van de uitgelegde routines staan ook op disk en + wel onder de naam CRUNCH.GEN. Veel plezier! + +Arjan Bakker diff --git a/future_disk/36/mathpack_2.md b/future_disk/36/mathpack_2.md new file mode 100644 index 0000000..1354380 --- /dev/null +++ b/future_disk/36/mathpack_2.md @@ -0,0 +1,109 @@ +Arjan heeft het over de Mathpack en ik snap er weer eens geen hout van... + + DE MATHPACK (2) + + + Een vorige keer schreef ik dat ik nog niet alle functies van + de MathPack had. Nu heb ik ze wel, dus kan ik weer een + lijstje met functies geven. Ik begin met ... + + + ...DATA-VERPLAATSINGEN + + Naam Adres Functie Type Verandert + MAF #2C4D DAC -> ARG Dubbele precisie A,B,D,E,H,L + MAM #2C50 (HL) -> ARG Dubbele precisie A,B,D,E,H,L + MOV8DH #2C53 (HL) -> (DE) Dubbele precisie A,B,D,E,H,L + MFA #2C59 ARG -> DAC Dubbele precisie A,B,D,E,H,L + MFM #2C5C (HL) -> DAC Dubbele precisie A,B,D,E,H,L + MMF #2C67 DAC -> (HL) Dubbele precisie A,B,D,E,H,L + MOV8HD #2C6A (DE) -> (HL) Dubbele precisie A,B,D,E,H,L + XTF #2C6F DAC <-> (SP) Dubbele precisie A,B,D,E,H,L + PHA #2CC7 (SP) -> ARG Dubbele precisie A,B,D,E,H,L + PHF #2CCC (SP) -> DAC Dubbele precisie A,B,D,E,H,L + PPA #2CDC ARG -> (SP) Dubbele precisie A,B,D,E,H,L + PPF #2CE2 DAC -> (SP) Dubbele precisie A,B,D,E,H,L + PUSHF #2EB1 (SP) -> DAC Enkele precisie D,E + MOVFM #2EBE (HL) -> DAC Enkele precisie B,C,D,E,H,L + MOVFR #2EC1 CBED -> DAC Enkele precisie D,E + MOVRF #2ECC DAC -> CBED Enkele precisie B,C,D,E,H,L + MOVRMI #2ED6 (HL) -> CBED Enkele precisie B,C,D,E,H,L + MOVRM #2EDF (HL) -> BCDE Enkele precisie B,C,D,E,H,L + MOVMF #2EE8 DAC -> (HL) Enkele precisie A,B,D,E,H,L + MOVE #2EEB (DE) -> (HL) Enkele precisie B,C,D,E,H,L + VMOVAM #2EEF (HL) -> DAC VALTYP B,C,D,E,H,L + MOVVFM #2EF2 (HL) -> (DE) VALTYP B,C,D,E,H,L + VMOVE #2EF3 (DE) -> (HL) VALTYP B,C,D,E,H,L + VMOVFA #2F05 ARG -> DAC VALTYP B,C,D,E,H,L + VMOVFM #2F08 (HL) -> DAC VALTYP B,C,D,E,H,L + VMOVAF #270D DAC -> ARG VALTYP B,C,D,E,H,L + VMOVMF #2710 (HL) -> DAC VALTYP B,C,D,E,H,L + + + REKENEN + + De volgende routine's zijn wel handig (niet allemaal, maar + de meeste wel): + + Naam Adres Functie Verandert + UMULT #314A DE = BC * DE Alles + ISUB #3167 HL = HL - DE Alles + IADD #3172 HL = HL + DE Alles + IMULT #3193 HL = HL * DE Alles + IDIV #31E6 HL = DE / HL Alles + IMOD #323A HL = DE mod HL Alles + + Het resultaat van deze functies komt ook op DAC+2 te staan + en VALTYP wordt op 2 gezet. Als je wilt rekenen, gebruik je + de routine's ISUB en IADD natuurlijk niet. De deling- en + vermenigvuldigingsroutine's zijn echter wel weer handig, als + je je code niet al te groot wilt laten worden tenminste. + + + VERGELIJKINGEN + + Met de volgende routine kun je getallen met elkaar + vergelijken. Na het aanroepen van een van deze functies + wordt in A een waarde teruggegeven. Als A 0 is, dan waren de + twee variabelen gelijk, als A 1 is, dan was de linker + variabele kleiner dan de rechter en als A 255 is, dan was de + linker groter dan de rechter variabele. De routines + veranderen overigens alle registers. + + Naam Adres Functie Precisie + FCOMP #2F21 Vergelijk CBDE met DAC Enkel + ICOMP #2F4D Vergelijk DE met HL Integer + XDCOMP #2F5C Vergelijk ARG met DAC Dubbel + + De routine ICOMP is wat mij betreft overbodig, want die zit + ook al gewoon in de BIOS (DCOMPR - RST #20) en meestal zal + je de code van die routine voor de snelheid ook al direct in + je routine zetten. + + + SLECHTE CODE + + Wat overigens opvalt bij het bestuderen van de routine's van + de Mathpack, is dat de routine's niet altijd gemaakt zijn op + snelheid. Zo kom je bijvoorbeeld de volgende source tegen + (met fictieve namen eventjes): + + move: ld a,(hl) + ld (de),a + inc hl + inc de + djnz move + ret + + Dit kun je veel beter gewoon met LDIR doen. Register C wordt + dan wel aangepast wat eerder niet gebeurde, dus even + PUSH'en, POP'en register B 0 maken is wel noodzakelijk. Op + een Turbo R kun je dit makkelijk aanpassen (bij de + RAM-mode), op een MSX2(+) zal het heel wat meer moeite + kosten. + + De volgende keer komen de resterende routine's van de + MathPack aan bod. + + + Arjan Bakker diff --git a/future_disk/36/recursie_2.md b/future_disk/36/recursie_2.md new file mode 100644 index 0000000..c4f7d42 --- /dev/null +++ b/future_disk/36/recursie_2.md @@ -0,0 +1,121 @@ +Dit is alweer het negende en laatste deel van de PASCAL cursus door de enige echte Jeroen Smael (NvdR: yeaaaah!!)... + + RECURSIE + + + ���� Ja, je leest het goed, dit deel gaat over recursie. Dat + ���� is ook waar we vorige keer gebleven waren, dus..... + ���� Goed, niet te veel intro gezeik, ik ga gewoon beginnen + ���� en dan zien we wel waar we uitkomen. + + Recursie (2) + + Wat is recursie? Recursie is (letterlijk) herhalen. Wat kun je + ermee? Heel veel, maar dat zal (hopelijk) nog wel duidelijk + worden. Een klassiek voorbeeld van recursie is machtsverheffen. + + MACHTSVERHEFFEN + + Wat is machtsverheffen? + + x^n = x^(n-1)*x + x^(n-1) = x^(n-2)*x + x^(n-2) = x^(n-3)*x + + Ok, je begrijpt het nu wel. De vraag is alleen wanneer stop ik + (terminate). Ik stop als (n-?) gelijk aan 0 is. Waarom? Als + (n-?) gelijk aan nul is dan krijg ik x^0 en dat is ALTIJD 1. + De functie ziet er dan als volgt uit: + + PROCEDURE Macht2(n : integer) : integer; + + BEGIN + IF n=0 THEN + Macht2=1 + ELSE + Macht2=Macht2(n-1)*2 + END; + + Bovenstaand is om elke willekeurige (positieve) macht van 2 te + berekenen (dat zit immers niet standaard in PASCAL). + Bijzonderheden zijn dat de functie zichzelf aanroept + (Macht2=Macht2(n-1)*2). Dat zou eigenlijk niet kunnen, omdat + de functienaam eigenlijk alleen aan de linkerkant van het = + teken mag staan (voor een toewijzing). Maar mag in dit geval + wel. + + IS DIT ALLES? + + Nee, dit is nog lang niet alles, maar het volgende (en tevens + laatste) voorbeeld is wel iets lastiger. Waarom? Omdat dit een + voorbeeld van backtracking is. Wat is Backtracking? + Backtracking wordt gebruikt voor zoek algoritmen. + + Backtracking + + Stel je staat in een doolhof. Wat doe je? Je gaat zoeken + natuurlijk, maar hoe? Als een kip zonder kop lijkt me niet erg + verstandig, want dan kom je nooit waar je wil zijn (de + uitgang). Dus ga je systematisch zoeken. Maar hoe doe je + dat? Als je veel tijd hebt (en wat heb je anders in een + doolhof) dan ga je altijd rechts. Is dat niet meer mogelijk, + dan ga je rechtdoor. Gaat dat niet meer, dan ga je links. Gaat + dat niet meer, dan ga je terug tot de plaats waar je als + laatste een keus moest maken en doet daar hetzelfde. Op die + manier kom je waar je wezen moet (bij de uitgang). Wat je + natuurlijk niet moet doen (maar wat ik vergeten ben te zeggen) + is over je eigen weg lopen (dus als je er al geweest bent, dan + ga je niet verder, omdat je anders in een kring gaat lopen). + + + Implementatie + + Ik ga de pseudo code van de implementatie geven, zodat je die + zelf uit kunt werken. Je moet dan wel zelf de hele + datastructuur opzetten, want dat doe ik niet voor je. Hier + gaat 'ie: + + PROCEDURE ZoekUitgang(Doolhof , Locatie , Gevonden); + + BEGIN + IF Locatie is buiten THEN + Gevonden = TRUE + ELSE + BEGIN + IF mogelijk naar rechts THEN + ZoekUitgang(Doolhof(markeer Locatie) , + Locatie + 1 naar rechts , Gevonden); + IF NOT Gevonden & mogelijk naar voren THEN + ZoekUitgang(Doolhof(markeer Locatie) , + Locatie + 1 naar voren , Gevonden); + IF NOT Gevonden & mogelijk naar links THEN + ZoekUitgang(Doolhof(markeer Locatie) , + Locatie + 1 naar links , Gevonden); + END; + END; + + Dat is alles. Hier horen natuurlijk een paar opmerkingen bij + en wel de volgende: + - Doolhof is een array waar de doolhof in staat en tevens of + je er geweest bent. + - Locatie is je 'X en Y' positie in de doolhof + - mogelijk is een functie die aangeeft of je die richting uit + mag (dit kun je ook de de procedure ZoekUitgang laten doen, + aangezien in een muur ook niet buiten is). + - markeer locatie is in Doolhof aangeven dat je er geweest + bent (dat moet je daarna wel weer verwijderen, anders zoek + je niet alles af). + + + WAT MOET IK ZEKER WETEN + + Wat je zeker moet weten is dat de MSX Turbo PASCAL v3.3 geen + recursie aankan. "Wat, geen recursie, waarom heb je ons dit + dan allemaal verteld?" + Omdat je recursie wel aan kunt zetten. Hoe? Door de $A+ optie + te gebruiken. Vergeet dit niet, anders klopt er niets van je + baksels (zelfs het machtsverheffen werkt dan al niet). + + Dat was het, + + Jeroen 'Backtracking' Smael diff --git a/future_disk/36/rom_images_laden.md b/future_disk/36/rom_images_laden.md new file mode 100644 index 0000000..c19e4b8 --- /dev/null +++ b/future_disk/36/rom_images_laden.md @@ -0,0 +1,112 @@ +ROM images, laat IK daar nu geen reet van snappen. + + ROM-IMAGES LADEN + + + Op de CD's van MCCM staan heel wat rom-images. Ook op andere + CD's (die illegaal zijn) en via internet (idem dito) zijn + heel wat roms te verkrijgen. Op een MSX-emulator zijn deze + eenvoudig te gebruiken, maar op een MSX is het een stuk + lastiger. + + Er is een programmaatje dat rom-images inlaadt en start, + maar bij mij werken de meeste spelletjes niet of niet + goed. Ik heb geen DOS2, dus ik denk dat het daar aan ligt. + In deze tekst zal ik beschrijven hoe je een programaatje + kunt maken en toch rom-images (van 16kB) kunt gebruiken, en + natuurlijk staat een simpele lader ook op de FD. + + De rom-images beginnen met de letters AB en vervolgens 2 + bytes die het adres weergeven waar na initialisatie heen + wordt gesprongen. De letters AB mag je wissen, zodat het + spel niet automatisch opstart na het resetten. + + De 2 bytes na AB kun je gebruiken om te kijken op welk adres + je het programma moet zetten. Als het adres groter is dan + #3FFF, dan kun je de rom-image op het interval #4000-#7FFF + laden en anders vanaf adres #0000. + + Verder moet er op pagina 1 en soms op 0 ram geschakeld zijn. + Onder DOS is dit altijd het geval, maar onder BASIC niet. Je + kunt met het volgende programmaatje op pagina 1 tot en met 3 + hetzelfde ram-slot selecteren. Als op pagina 0 ook RAM moet + staan, dan moet je vier keer RRA gebruiken in plaats van + twee keer. + + in a,(#a8) ; Lees huidige stand + and 240 ; Hoogste 4 bits zijn onder + ld b,a ; BASIC altijd al RAM + rra ; Schuif de bits naar rechts + rra + or b ; Oude stand erbij + out (#a8),a ; Schrijf slotstand weg + + Zo, nu weet je alles om een 16kB rom-image te gebruiken. Nu + gaan we daadwerkelijk het programma maken (niet helemaal + natuurlijk, maar alleen de code waar je problemen mee kunt + krijgen. De volledige source staat op deze FD in de file + ROM16.LZH, waar ook een simpele BASIC-lader in staat) + waarmee je 16kB rom-images mee kunt inladen. Het programma + aanpassen voor 32kB is trouwens erg makkelijk. + + org #c000 + + Onder BASIC erg logisch, want op adres #4000-#7FFF mag niets + geladen worden. + + ld de,fcb + ld c,open_file + call bdos ; open de rom-image + + call initFCB ; initialiseer FCB om te + ; laden + + ld de,#8000 + ld c,setdta ; Zet adres waar de data + call bdos ; terecht komt + + ld hl,16384 + ld de,fcb + ld c,read_block + call bdos ; Lees file in + + di ; Interrupts uit + + call selram ; Schakel RAM in + + ld hl,#8000 ; Wis A van AB zodat rom niet + ld a,0 ; na reset opstart + ld (hl),a + ld bc,#4000 ; Grootte + ld de,#4000 ; Bestemming + ld a,(#8003) ; Check startadres van rom + cp #40 + jp nc,jump1 ; >#4000 -> Bestemming is + ; goed + + ld de,#0000 + + jump1: ldir ; Verplaats + + ld hl,(#8002) ; Laadt start adres + jp (hl) ; en spring ernaar toe + + + Het gebruik van ROM-images die groter dan 32kB zijn is veel + lastiger, omdat die schakelroutine's gebruiken die bij + bepaalde roms de data op andere adressen schakelen dan bij + andere roms. Daarom heeft fMSX bij het selecteren van roms + een optie om de cartridge-type te kiezen, zodat de roms wel + werken. Het programma LOADROM (voor MSX) kan wel mega-roms + aan, maar dat programma werkt alleen onder DOS2 goed en laat + ik die nou net niet hebben. Een ander probleem is het + geheugen, want bij mega-roms heb je gewoon meer dan 128kB + geheugen nodig. Ook een probleem is dat de roms zelf ook + naar ram schrijven en dus je kopie kunnen overschrijven + waardoor alles in de soep loopt. + + + Veel plezier en succes! + + +Arjan Bakker diff --git a/future_disk/37/advanced_basic_6.md b/future_disk/37/advanced_basic_6.md new file mode 100644 index 0000000..42384c4 --- /dev/null +++ b/future_disk/37/advanced_basic_6.md @@ -0,0 +1,102 @@ +Een zeer nuttige tekst... + + ADVANCED BASIC CURSUS 6 + + + Eindelijk, het laatste deel van deze cursus. Ik heb het + gevoel dat geen hond zich interesseert in deze cursus. + Het aantal personen die Advanced BASIC kochten zijn op een + hand te tellen, ondanks de goede recensies. Blijkbaar + programmeert niemand meer in BASIC, of is men gewoon te + gierig om wat geld uit te geven? Hoe dan ook, dit is het + laatste deel van deze cursus en daar ben ik blij om. Nu kan + ik wat meer tijd zinniger besteden, bijvoorbeeld aan het + programmeren van een MoonSound-replayer voor de FD. + + + ENOUGH CRAP + + Goed, ik zal maar snel verdergaan met de cursus, want daar + gaat het toch om. Zoals gezegd gaat deze aflevering over + hybride-programmeren onder Advanced BASIC. Hybride + programmeren wil zeggen dat er 2 of meer programmeertalen + met elkaar gecombineerd worden, zoals BASIC met ML of PASCAL + met ML. + + BASIC is over het algemeen prima te combineren met ML, maar + wat toch onhandig is, is het doorgeven van veel parameters + aan de routines. Meestal is het een kwestie van de hele zooi + ergens POKE'n, maar dat is niet echt netjes. Met Advanced + BASIC gaat dit een stuk makkelijker, want je kunt namelijk + gewoon met CALL REGreg(x) een waarde aan een register geven. + Alle registers zijn toegestaan, op de stackpointer, program- + counter en de registers I en R na. + + Nadat je alle registers hebt gevuld, kun je met _CALL(adres) + een ML-routine op het aangegeven adres gebruiken. Je kunt de + ML-routine's natuurlijk ook met DEFUSR=x:A=USR(0) aanroepen, + maar dan worden er geen registers doorgegeven. + + Natuurlijk kun je, als je de registers kunt wijzigen, ook de + registers weer uitlezen. Dit kan met het commando CALL + GETreg(adres). Het register aangeduidt met 'reg' wordt dan + gezet in het aangegeven adres. Zoals al in een vorige deel + van deze cursus gezegd werd, kun je met een truukje ook een + variabele als bestemming gebruiken. Dit gaat als volgt: + 10 DEFINT A-Z + 20 _CALL(&H9F) + 30 T=0:_REGA(VARPTR(T)) + 40 PRINT CHR$(T) + RUN + + Dit programmaatje roept routine CHGET op adres &H9F aan, + welke de ingedrukte toets in register A zet. Vervolgens kun + je met VARPTR(T) het adres van variabele T krijgen en dat + adres wordt dus gevuld met de waarde van de ingedrukte + toets. Tot slot wordt de ingedrukte toets eventjes geprint. + Let erop dat als je VARPTR(var) gebruikt, de variabele al + wel moet bestaan. Daarom wordt de variabele T eerst + aangemaakt in regel 30. Doe je dit niet, dan krijg je een + botte Illegal function call. De variabele moet trouwens ook + integer zijn, anders kan het fout gaan. + + +ADVANCED BASIC & KUN-BASIC + + Advanced BASIC en KUN-BASIC kunnen met elkaar gecombineerd + worden. Je moet wel eventjes een heel klein programmaatje + maken, maar dat is zo simpel als wat. De truuk is dat je de + beide uitbreidingen allebei in een andere geheugenpagina zet + en de juist pagina inschakelt als je een extra commando wilt + gebruiken. + + Het volgende programmaatje laad Advanced BASIC en KUN-BASIC + in het geheugen: + + 10 OUT &HFD,2:BLOAD "ADVBASIC.BIN",R + 20 OUT &HFD,4:BLOAD "COMPILER.BIN",R + + Als je nu een commando van Advanced BASIC wilt gebruiken, + schakel je eerst Advanced BASIC in met OUT &HFD,2 en dan kun + je het commando gebruiken. Wil je KUN-BASIC gebruiken, dan + kun je die inschakelen met OUT &HFD,4. + + Een nadeel is dat je geen commando's van Advanced BASIC + binnen een stuk programma dat gecompileerd wordt. Het + volgende kan dus niet: + 10 OUT &HFD,4 ' Schakel KUN in + 20 _TURBO ON + 30 PRINT "This won't work" + 40 OUT &HFD,2 ' Schakel Advanced BASIC in + 50 _WINDOW(0,0,80,3) + 60 OUT &HFD,4 ' Schakel KUN in + 70 _TURBO OFF + RUN + + Het programma loopt nu vast op het commando _WINDOW. + + Als het goed is, heb ik nu alle commando's behandeld. Zo + niet, pech gehad, want ik heb geen zin om ook nog maar ��n + woord aan dit onderwerp vuil te maken. + + Arjan Bakker diff --git a/future_disk/37/assembly_cursus_6.md b/future_disk/37/assembly_cursus_6.md new file mode 100644 index 0000000..dac6008 --- /dev/null +++ b/future_disk/37/assembly_cursus_6.md @@ -0,0 +1,830 @@ +De assembly cursus gaat vrolijk verder... + + ASSEMBLY (6) + + + Zoals ik de vorige keer al zei ga ik het deze keer hebben + over .LIB-files. Omdat dit nogal een uitgebreid onderwerp + is, beslaat deze tekst 3 delen. Het eerste deel behandelt + wat theorie en een klein stukje van de source van de + LIB-maker, deel twee gaat over de rest van die source en + deel 3 van deze cursus legt uit hoe je .LIB-files moet + gebruiken in je eigen programma's. + + + WAT ZIJN LIB-FILES? + + Een LIB-file is niets anders dan een file waarin alle files + die een programma gebruikt zitten (vandaar LIB, van + LIBrary). Een goed voorbeeld van deze files is bijvoorbeeld + Smumpkin 3, Muzax 3 en de Final Fantasy Slide Show die op + disk A van FD 35 stond. + + + WAAROM LIB-FILES? + + Waarom zou je LIB-files gebruiken als het gebruiken van + gewone files veel makkelijker is? Hier is een aantal redenen + voor, namelijk: + + -Het neemt minder ruimte in beslag: Stel je hebt 4 files van + (ik noem maar wat) 256 bytes. Als deze files los in de + directory zouden staan, namen ze ieder (op een diskette) + ��n kilobyte in beslag, dus met z'n allen is dat 4 kB. In + een LIB-file nemen ze echter maar 1 kB in beslag, omdat de + files aan elkaar worden geplakt. + + -Het is sneller: Telkens als een nieuwe file wordt geopend, + moet de computer de juiste filenaam in de directory zoeken. + Dit kost aardig wat tijd, zeker als de directory helemaal + vol staat en de te zoeken file de laatste file uit de + directory is. Een andere manier om snel te laden is alles + op sector zetten. Dit neemt wel minder ruimte in beslag dan + gewoon de bestanden op diskette houden, maar LIB-files zijn + altijd nog effici�nter. + + -Er passen (in theorie) oneindig veel files in: In een + directory passen (normaal gesproken) slechts 112 files. + Het aantal files in een LIB-file is echter oneindig, voor + zover de diskruimte het toelaat tenminste. + + -Het is veel netter dan gewoon alle files op disk kwakken: + Een directory vol met bestanden is niet echt netjes, zeker + als je meerdere programma's op ��n diskette zet. + + + NADELEN + + Er zijn natuurlijk ook wat nadelen aan het gebruik van + LIB-files, namelijk: + + -De directory van een LIB-file moet permanent in het + geheugen staan (hoeft eigenlijk niet, maar het is wel v��l + sneller). Een erg groot nadeel is dit niet, want meestal + zal je directory niet meer dan 1 kB in beslag nemen. De + routine die straks volgt gebruikt per file 16 bytes, dus + met 64 files heb je 1 kB vol. Gebruik je echter de + effici�ntste methode, dan kun je in 1 kB ruim 200 files + zetten! Dit lijkt mij meer dan genoeg. + + -Het is wat extra programmeerwerk. Dit valt in de praktijk + echter best wel mee, zelfs ik had er geen moeite mee. Dit + geldt natuurlijk alleen voor de eerste keer, want je + volgende programma's kun (moet) je gebruik maken van + dezelfde routine's. + + +DE OPZET VAN HET PROGRAMMA + + Ik heb gekozen voor een programma dat onder DOS werkt, om de + simpele reden dat daar gewoon meer geheugen beschikbaar is. + Verder verwacht het programma de bestanden op drive A en + komt de LIB-file op drive B. Dit is echter zeer makkelijk + aan te passen. Harddisk-gebruikers zullen gewoon alles op + ��n drive doen, net zoals mensen met maar ��n diskdrive + (tenzij je een lekker grote ramdisk aan kunt maken). Ook + zijn er geen foutmeldingen. Tot slot staan de namen van de + bestanden die in de LIB-file moeten komen in de source zelf, + evenals de naam van de aan te maken LIB-file. Dit heb ik + gedaan om de source niet al te lang te laten worden, want + een command-line interpreter kost aardig wat regeltjes. Ook + is het niet de bedoeling dat ik alles voorkauw, en + natuurlijk ben ik lui! Een andere geldige reden is dat de + ruimte van de command-line aardig beperkt is. De beste + oplossing zou gewoon zijn om alle bestanden in een tekstfile + te zetten en de naam daarvan door te geven aan het + programma. Maar goed, dat mogen jullie zelf allemaal wel + doen. + + + DE SOURCE + + Okay, dan komt nu het programma zelf. + + org #0100 + + bdos: equ #05 + setdta: equ 26 ; zet lees/schrijf-adres + open_file: equ 15 ; open file + close_file: equ 16 ; sluit file + create_file: equ 22 ; maak file aan + read_block: equ 39 ; laad van disk + write_block: equ 38 ; schrijf naar disk + + entry_length: equ 11 + 2 + 3 + + Het programma werkt onder MSX-DOS, dus een org #0100 is op + z'n plaats (alhoewel dit wel weggelaten kan worden bij + GEN80. Zo is het echter voor jezelf wel duidelijk dat het + een DOS-programma is). Verder worden wat naampjes voor disk- + gebruik gedefinieerd en de lengte die de naam en data van + een bestand in de directory moet innemen. Dit is hier in + totaal 16 bytes, namelijk 11 voor de filenaam, 2 voor de + lengte en 3 voor de plaats in de LIB-file. Dit heeft echter + als beperking dat de maximale grootte van een file die in de + LIB-file moet komen 64kB is. Deze grootte zul je echter + alleen maar overschrijden bij samplekits voor de Moonsound, + dus zo'n ramp is dat ook weer niet. Ik ga verder... + + MAIN + + call count_files ; tel aantal files + ld (files),bc + + call calc_length ; bereken lengte + ; directory + ld (dir_length),hl + + call make_dir ; maak directory + + call save_dir ; bewaar directory + + call store_files ; bewaar files + + ld de,fcb2 + ld c,close_file + call bdos ; klaar! + ret + + Dit is de hoofdlus van het programma. De routine count_files + telt het aantal files die in de LIB-file moeten komen, + calc_length berekent de lengte van de directory, make_dir + maakt de directory aan, save_dir schrijft de directory weg + en store_files copi�ert alle files naar de LIB-file. + Tenslotte wordt de LIB-file gesloten en zijn we klaar. + + COUNT FILES + + ; Tel aantal files + ; In: - + ; Uit: BC: aantal files + ; Verandert: AF,BC,DE,HL + count_files: ld hl,file_names + ld bc,0 + ld de,11 + + count_files1: ld a,(hl) + or a + ret z + inc bc + add hl,de + jr count_files1 + + Deze routine telt het aantal files in de directory. Dit + wordt gedaan door te kijken of de byte op adres HL een 0 is. + Als dat zo is, zijn alle files geteld en anders wordt BC + verhoogd en wordt de zooi herhaald. + + + CALCULATE LENGTH + + ; Bereken lengte directory + ; In: BC: aantal files + ; Uit: HL: lengte directory + ; Verandert: AF, BC, DE, HL + calc_length: ld hl,3 + ld de,entry_length + + calc_length1: ld a,b + or c + ret z + add hl,de + dec bc + jr calc_length1 + + Deze routine berekent de lengte van de directory. Dit wordt + gedaan door dom de waarde entry_length herhaald op te tellen + en vervolgens er 3 bij op te tellen. De eerste 2 bytes van + de directory worden namelijk gebruikt om het aantal files + in de directory aan te geven en de laatste byte van de + directory wordt gebruikt om aan te geven dat alle files + geweest zijn. Natuurlijk kan het berekenen sneller gedaan + worden door een vermenigvuldigingsroutine te gebruiken, maar + dit was eventjes wat sneller om te programmeren (ja, ik ben + lui!). + + De routine om de directory te maken is behoorlijk lang, + daarom zal ik tussen de regels door wat opmerkingen maken en + niet pas aan het einde. + + + MAKE DIRECTORY + + ; Maak directory + ; In: HL: lengte directory + ; Uit: - + ; Verandert: AF, BC, DE, HL + make_dir: ld (getal1),hl + ld hl,0 + ld (getal1+2),hl + + ld hl,file_names + ld de,directory + ld bc,(files) + + Dit stukje initialiseert de routine. Op het adres 'getal1' + staat de offset waar de files na de directory van de + LIB-file beginnen. Verder wordt het adres waar de filenamen + staan geladen (HL), het adres waar de directory moet komen + geladen (DE) en het aantal files geladen (BC). + + make_dir1: push bc + + push hl + push de + + ld bc,11 + ld de,fname1 + ldir ; filenaam naar FCB + + pop de + pop hl + ld bc,11 + ldir ; filenaam naar directory + + Register BC hebben we pas op het einde weer nodig dus + PUSH'en we die even weg. Vervolgens moet de filenaam twee + keer gecopi�erd worden, namelijk naar de FCB en naar de + uiteindelijke directory. + + push hl + + push de + ld de,fcb1 + ld c,open_file + call bdos + ld de,fcb1 + ld c,close_file + call bdos + pop de + ld hl,(length1) + + De file wordt geopend en de lengte wordt opgevraagd. + + ld a,l + ld (de),a + inc de + ld a,h + ld (de),a + inc de + + De lengte van de file wordt in de directory gezet. + + ld ix,getal1 ; bewaar positie in file + ld a,(ix) + ld (de),a + inc de + ld a,(ix+1) + ld (de),a + inc de + ld a,(ix+2) + ld (de),a + inc de + + De plek waar de file in het bestand staat wordt in de + directory gezet. Dit is een 24-bits getal, daarom wordt dit + eventjes met register IX gedaan. + + push de + + ld iy,getal2 + ld (iy),l + ld (iy+1),h + ld ix,getal1 + call add_32bit + + De lengte van de file wordt opgeteld bij de positie in de + LIB-file. Hiervoor wordt een 32-bits optel-routine gebruikt, + welke 'getal1' en 'getal2' gebruikt als parameters en het + resultaat stopt in 'getal1'. + + pop de + pop hl + pop bc + dec bc + ld a,b + or c + jp nz,make_dir1 + xor a + ld (de),a + ret + + Nu worden alle registers teruggehaald en wordt er een lusje + gemaakt om de boel te herhalen. Als alle files geweest zijn, + wordt er nog even een 0 weggeschreven en dan is deze routine + klaar. + +LEES VERDER IN DEEL 2 +De assembly cursus gaat vrolijk verder... + + ASSEMBLY (6)-2 + + +We gaan weer verder waar we gebleven waren... + + + SAVE DIRECTORY + + ; Bewaar directory + ; In: - + ; Uit: - + ; Verandert: AF, BC, DE, HL + save_dir: ld hl,lib_name + ld de,fname2 + ld bc,11 + ldir + + ld de,fcb2 + ld c,create_file + call bdos ; cre�er file + + call intfcb2 + + ld de,files + ld c,setdta + call bdos + + ld de,fcb2 + ld c,write_block + ld hl,(dir_length) + call bdos ; schrijf directory weg + ret + + Deze routine bewaart de net aangemaakte directory. Eerst + wordt de naam van de library naar het FCB gecopi�erd. + Vervolgens wordt de file gecre�erd en wordt het FCB + geinitialiseerd voor het schrijven. Daarna wordt het Disk + Transfer Address gezet op het adres waar het aantal files + staat en tot slot wordt de directory weggeschreven. + + + STORE FILES + + ; Bewaar files in .LIB-file + ; In: - + ; Uit: - + ; Verandert: AF, BC, DE, HL + store_files: ld bc,(files) + ld hl,file_names + + Het aantal files wordt in register BC geladen en het adres + waar de filenamen staan in register HL. + + store_files1: push bc + + ld bc,11 + ld de,fname1 + ldir + push hl + + call clrfcb1 + + ld c,open_file + ld de,fcb1 + call bdos + + call intfcb1 + + De filenaam wordt gecopi�erd naar het FCB, het FCB wordt + vervolgens schoongemaakt en daarna wordt de file geopend. + Tot slot wordt het FCB ge�nitialiseerd. + + ld hl,(length1) + call copy_file ; kopieer file + + ld de,fcb1 + ld c,close_file + call bdos + + pop hl + pop bc + dec bc + ld a,b + or c + jp nz,store_files1 + ret + + In register HL komt de lengte van de file en die wordt + vervolgens gecopi�erd door de routine copy_file. De file + wordt daarna gesloten en dan wordt het zooitje herhaald. + + + COPY FILE + + ; Copieer file naar .LIB-file + ; In: HL: lengte file + ; Uit: - + ; Verandert: AF, BC, DE, HL + copy_file: push hl + ld c,setdta + ld de,directory + call bdos + pop hl + + Het lees/schrijfadres wordt op het adres gezet waar de + directory stond. + + copy_file1: ld de,32768 + xor a + sbc hl,de ; file >32768 bytes? + jp c,copy_file2 ; Nee, copieer rest + + push hl + ld hl,32768 + ld de,fcb1 + ld c,read_block + call bdos + + ld hl,32768 + ld de,fcb2 + ld c,write_block + call bdos + pop hl + jp copy_file1 + + Er wordt gekeken of de file groter is dan 32 kB. Als dat zo + is, dan wordt er 32 kB ingeladen en vervolgens wegge- + schreven. Daarna wordt de routine herhaald. + + copy_file2: add hl,de + push hl + ld de,fcb1 + ld c,read_block + call bdos + pop hl + ld de,fcb2 + ld c,write_block + call bdos + ret + + De resterende data van de file wordt ingelezen en weggeschreven + + ; Tel twee 32-bits getallen op + ; In: IX: adres getal 1 + ; IY: adres getal 2 + ; Uit: getal 1 gevuld met resultaat + ; Verandert: BC,DE,HL + add_32bit: ld l,(ix+0) + ld h,(ix+1) + + ld e,(iy+0) + ld d,(iy+1) + + ld c,(ix+2) + ld b,(ix+3) + add hl,de + jr nc,add_32bit1 + inc bc + add_32bit1: ld (ix+0),l + ld (ix+1),h + + Deze routine telt twee 32-bits getallen bij elkaar op. In IX + staat het adres van het eerste getal en in IY het adres van + het tweede getal. Register HL en DE worden geladen met het + eerste word van de 32-bits waarde en register BC met het + tweede word van het eerste getal. Daarna wordt DE bij HL + opgeteld en als er een overflow plaats vindt, wordt het + tweede word met ��n verhoogd. Tot slot wordt het eerste word + weggeschreven. + + ld l,(iy+2) + ld h,(iy+3) + add hl,bc + ld (ix+2),l + ld (ix+3),h + ret + + Het tweede word van het tweede getal wordt in register HL + geladen en wordt bij het tweede word van het eerste getal + opgeteld en vervolgens opgeslagen. + + ; Maak FCB 1 schoon + ; In: - + ; Uit: - + ; Verandert: AF, BC, DE, HL + clrfcb1: ld hl,fcbdat1 + ld bc,25 + xor a + ld (hl),a + ld de,fcbdat1 + 1 + ldir + ret + + Deze routine maakt het eerste FCB snel schoon met een + truukje met LDIR. Het eerste adres wordt namelijk eerst op 0 + gezet en het bestemmingsadres wordt dan ��n hoger dan het + beginadres. Met LDIR wordt vervolgens het FCB gevuld met + nullen. + + ; Initialiseer FCB 1 + ; In: - + ; Uit: - + ; Verandert: AF, HL + intfcb1: ld hl,0 + ld (fcb1 + 12),hl + ld (fcb1 + 33),hl + ld (fcb1 + 35),hl + xor a + ld (fcb1 + 32),a + inc hl + ld (fcb1 + 14),hl + ret + + Deze routine initialiseert het eerste FCB voor het lezen. + Het current block (fcb1 + 12) wordt op 0 gezet, evenals + random record (fcb1+32/33/35). Tot slot wordt de record- + lengte op 1 gezet. + + ; Initialiseer FCB 2 + ; In: - + ; Uit: - + ; Verandert: AF, HL + intfcb2: ld hl,0 + ld (fcb2 + 12),hl + ld (fcb2 + 33),hl + ld (fcb2 + 35),hl + xor a + ld (fcb2 + 32),a + inc hl + ld (fcb2 + 14),hl + ret + + Deze routine doet hetzelfde als de routine intfcb1. + + getal1: defw 0,0 ; opslagplaats voor de twee + getal2: defw 0,0 ; 32-bits getallen + + dir_length: defw 0 ; lengte van directory + + ; Het eerste FCB + fcb1: defb 1 ; drive (0=default, 1 = A:) + fname1: defm " " + fcbdat1: defb 0,0,0,0 + length1: defb 0,0,0,0,0,0,0,0,0,0,0 + defb 0,0,0,0,0,0,0,0,0,0,0 + + ; Het tweede FCB + fcb2: defb 2 ; drive (0=default, 2 = B:) + fname2: defm " " + defb 0,0,0,0,0,0,0,0,0,0,0,0,0 + defb 0,0,0,0,0,0,0,0,0,0,0,0,0 + + ; Naam van de te maken .LIB-file + lib_name: defm "???????????" + + ; Lijst met files die in de .LIB-file moeten + file_names: defm "???????????" + + defb 0 ; 0 = laatste gehad + + files: defw 0 ; bewaarplaats aantal files + directory: nop + + Vul bij lib_name de aan te maken LIB-file in en bij + file_names de bestanden die je erin wilt hebben. De lengte + van de naam is 11 letters en er mag GEEN '.' gebruikt + worden. Na de laatste file moet een 'defb 0' staan, om aan + te geven dat er geen files meer komen. + + +LEES VERDER IN DEEL 3 +De assembly cursus gaat vrolijk verder... + + ASSEMBLY (6)-3 + + +We gaan weer verder waar we gebleven waren... + + Tot slot bespreek ik de routine's om de LIB-files in je + eigen programma's te gebruiken (m��r wil ik ook niet meer + doen). Deze routine's zijn stukken simpeler, daarom besteed + ik ook maar ��n tekst aan dit gedeelte. + + Er zijn drie routine's nodig, namelijk een routine die de + file opent en de directory inleest, een routine die een file + opzoekt in de directory en de pointers goed zet en een + routine die een (gedeelte van een) file inlaadt. + + + DE SOURCE + + bdos: equ #f37d + fopen: equ 15 ; open file + fclose: equ 16 ; sluit file + rdblk: equ 39 ; lees blok + setdta: equ 26 ; zet lees/schrijfadres + + ; Routine's voor het gebruik van een .LIB-file + init_dir: jp load_dir ; laad directory in + file_find: jp search_file ; Zoek file + load_file: jp load_block ; Laad file in + + Dit zijn de routine's die het inlezen van de directory, het + zoeken van een file in de directory en het lezen van een + file uitvoeren. + + + LOAD DIRECTORY + + ; Laad directory + ; In: HL: Adres filename + ; DE: Bestemmingsadres directory + load_dir: push de + push de + push hl + + call clrfcb + + pop hl + + ld bc,11 + ld de,fname + ldir + + pop de + ld c,setdta + call bdos + + Het FCB wordt schoongemaakt, de naam van de LIB-file wordt + in het FCB gezet en vervolgens wordt het lees/schrijf-adres + gezet. + + ld de,fcb + ld c,fopen + call bdos + + call intfcb + + ld hl,2 + ld de,fcb + ld c,rdblk + call bdos + + De file wordt geopend, het FCB wordt ge�nitialiseerd en het + aantal files in de directory wordt gelezen (eerste 2 bytes). + + pop hl + ld c,(hl) + inc hl + ld b,(hl) + + ld hl,1 + ld de,11 + 3 + 2 ; lengte entry + calc_length: add hl,de + dec bc + ld a,b + or c + jp nz,calc_length + + Het aantal files komt in BC terecht en de lengte van de + directory wordt berekend. Dit kan wel beter met een echte + vermenigvuldigingsroutine, maar dit was eventjes sneller + programmeren. + + ld de,fcb + ld c,rdblk + call bdos ; Laad directory in + ret + + De directory wordt geladen en klaar is de routine. + + + SEARCH FILE + + ; Zoek file op in directory en stel record number in + ; In: HL: adres te laden file-naam + ; DE: adres directory + ; Uit: HL: lengte file + ; A: 0 indien gelukt, 255 indien mislukt + search_file: push hl + push de + + call cmp_str + + or a + jp z,search_file1 + + De file wordt vergeleken met de huidige file in de directory. + Als A nul is, is de file gevonden. + + pop de + ld hl,11 + 3 + 2 + add hl,de + ex de,hl ; DE = positie in directory + pop hl + jp search_file + + De pointer naar de directory wordt verhoogd en de routine + herhaalt zichzelf. + + search_file1: ex de,hl ; HL = adres in directory + + ld e,(hl) + inc hl + ld d,(hl) ; laad lengte + inc hl + push de + + De lengte van de file wordt uitgelezen en gePUSHed. + + ld de,fcb + 33 + ld bc,3 + ldir ; Record Number naar FCB + + xor a + ld (de),a + + De positie in de file wordt in het FCB gezet. + + pop hl ; lengte in HL + + pop de + pop de + ret + + De lengte van de file komt in HL en de routine is klaar. + + LOAD (PART OF) FILE + + ; Lees een (gedeelte van een) file in + ; In: HL: aantal te laden bytes + ; Opmerking: zelf bestemmingsadres goedzetten + load_block: ld de,fcb + ld c,rdblk + jp bdos + + Geen uitleg nodig lijkt mij. + + ; Vergelijk strings met elkaar + ; In: HL: adres eerste string + ; DE: adres tweede string + ; Uit: A: 0 = gelijk, anders = ongelijk + cmp_str: ld b,11 + + cmp_str1: ld a,(de) + cp (hl) + ret nz + inc hl + inc de + djnz cmp_str1 + xor a + ret + + Vergelijk twee strings met elkaar. Ook hier geen uitleg + nodig, lijkt mij. + + ; Initialiseer FCB + ; in: niets + ; uit: niets + ; Verandert: alles + clrfcb: ld hl,fcbdat + ld bc,25 + xor a + ld (hl),a + ld d,h + ld e,l + inc de + ldir + ret + + Zie vorige tekst. + + ; init fcb + ; in: niets + ; uit: niets + ; Verandert: af, hl + intfcb: ld hl,0 + ld (fcb+12),hl ; bloknummer op 0 + + ld (fcb+33),hl ; random block op 0 + ld (fcb+35),hl + + xor a + ld (fcb+32),a ; current record op 0 + + inc hl + ld (fcb+14),hl ; bloklengte op 1 + ret + + Zie vorige tekst. + + ; file control block + fcb: defb 0 ; drive + fname: defm "???????????" ; filename + fcbdat: defb 0,0 ; current block + defb 0,0 ; block lengte + length: defb 0,0,0,0 ; file lengte + defb 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + Ook in deze routine's zijn natuurlijk weer verbeteringen + mogelijk. Zo zou je een error kunnen laten geven als een + file niet gevonden wordt, al is dat niet echt nodig als je + een programma uitbrengt. + + De sources staan natuurlijk ook op disk. De library-maker + heet MAKELIB.GEN en de library-lezer heet USELIB.GEN. Het is + niet verboden om de sources in je eigen programma's te + gebruiken, maar het is beter als je je eigen routine's + maakt. Tot de volgende keer! + + Arjan Bakker diff --git a/future_disk/37/mathpack_3.md b/future_disk/37/mathpack_3.md new file mode 100644 index 0000000..835f849 --- /dev/null +++ b/future_disk/37/mathpack_3.md @@ -0,0 +1,91 @@ +Het laatste deel over de MATH PACK... + + DE MATH-PACK (3) + + + In dit laatste deel over de math-pack komen de wat comple- + xere routine's aan bod, en dan voornamelijk de string- + routine's. + + De routine FIN (&H3299) zet een string om naar een decimaal + getal in DAC. Hiervoor heeft deze routine register HL nodig + om het startadres van de string aan te geven en register A om + het eerste teken te weten. Als resultaat staat op DAC dus het + getal. Register C bevat de waarde 255 als de string geen punt + bevatte en de waarde 0 als er wel een punt in stond en regis- + ter B bevat het aantal cijfers achter de punt. + + De routine's FOUT (&H3425) en PUFOUT (&H3426) zetten het + getal in DAC om naar een string. Het verschil tussen beide + routine's is dat FOUT de string niet formatteerd en PUFOUT + wel en dat PUFOUT de DAC positief maakt. + + De invoer en uitvoer is bij beide routine's hetzelfde. + Register A geeft het formaat van de string aan, waarbij de + afzonderlijke bits de volgende betekenis hebben: + + bit 7: 0 = ongeformatteerd, 1 = geformatteerd + bit 6: 0 = zonder komma's , 1 = met komma's om de drie + cijfers + bit 5: 0 = niets , 1 = voorafgaande spaties worden + opgevuld met punten + bit 4: 0 = niets , 1 = "$" wordt voor de waarde + gezet + bit 3: 0 = niets , 1 = "+" wordt voor de waarde + gezet (indien de waarde positief was) + bit 2: 0 = niets , 1 = +/- wordt achter de waarde + gezet + bit 1: niet gebruikt + bit 0: 0 = fixed point , 1 = floating point + + Register B geeft het aantal cijfers voor de punt aan en + register C geeft het aantal cijfer na de punt aan (inclusief + de punt). Als er dus 3 tekens na de punt komen, moet je de + waarde 4 in register B zetten. + + Na het uitvoeren van ��n van deze routine's komt in register + HL het adres van de string. + + De routine's FOUTB (&H371A), FOUTO (&H371E) en FOUTH + (&H3722) zetten een integer getal in DAC+2/3 om naar + respectievelijk een binaire, octale en hexadecimale string. + Let er trouwens op dat VALTYP op 2 staat. Deze 3 routine's + hebben dus als resultaat een string waarvan het beginadres + in register HL komt te staan. + + + TYPE CONVERSIE + + De routine's FRCINT (&H2F8A), FRCSNG (&H2FB2) en FRCDBL + (&H303A) zetten het getal DAC om naar respectievelijk een + 2-byte integer (DAC+2/3), een enkele precisie waarde en een + dubbele precisie waarde. Na aanroep bevat VALTYP het type + van DAC (dus 2, 4 of 8) en zijn alle registers veranderd. + + De routine FIXER op adres &H30BE maakt van het getal DAC een + gehele waarde. Ook hier worden alle registers veranderd. + + + MACHTSVERHEFFEN + + Er zijn nog 3 extra routine's voor het machtsverheffen. + SGNEXP (&H37C8) is voor getallen van enkele precisie, DBLEXP + (&H37D7) is voor getallen van dubbele precisie en INTEXP + (&H383F) is voor 2-byte integers. De eerste 2 routine's + gebruiken DAC als basis en ARG als macht en de laatste + gebruikt DE als basus en HL als macht. Bij alle drie de + routine's wordt het resultaat in DAC gezet en worden alle + registers verandert. + + TOT SLOT + + Er is ook nog een routine om register HL decimaal op het + scherm te zetten, namelijk PRTHL (&H3412). Deze routine is + echter niet offici�el, maar werkt volgens mij wel altijd. + + Ik geloof dat ik nu wel alles over de math-pack heb + behandeld. Mocht ik echter nog wat onbehandelde dingetjes + tegenkomen, dan zal ik daar later op terugkomen maar wat mij + betreft is dit de laatste tekst over dit onderwerp. + +Arjan Bakker diff --git a/future_disk/38/assembly_cursus_7.md b/future_disk/38/assembly_cursus_7.md new file mode 100644 index 0000000..e5fa8bd --- /dev/null +++ b/future_disk/38/assembly_cursus_7.md @@ -0,0 +1,138 @@ +ASSEMBLY CURSUS 7 + + +Dit is alweer het zevende deel van de assembly cursus, +tenminste, als ik me niet vergis. Maar goed, het is niet +echt belangrijk om te weten welk deel het is want dat maakt +geen zak uit voor de inhoud. En nu ik het toch over de +inhoud heb, ik heb de laatste tijd moeite om een leuk onder- +werp te verzinnen. Mocht je dus eens een keer iets willen +weten, schrijf of bel ons even en wellicht krijg je op de +volgende FD dan al een antwoord. Maar goed, voor deze keer +heb ik nog wel een onderwerpje, namelijk werken met BCD- +getallen + + + BCD-GETALLEN + +Het idee voor dit onderwerp kreeg ik tijdens het maken van +het spelletje dat deze keer op de FD staat. Ik had namelijk +lange getallen nodig om de score aan te duiden en dan heb je +aan 16 bits niet genoeg. Je kunt dan wel gaan werken met 32 +bits getallen, maar het afdrukken daarvan gaat niet echt +snel en het is ook een beetje lastig om te programmeren. + +Nu zal een ervaren programmeur natuurlijk zeggen: Waarom +gebruik je niet de MathPack (MP)? Nou, dat zal ik eens +eventjes fijn uitleggen. Ten eerste is de MP mij te sloom, +omdat de MP ook rekening houdt met een komma, negatieve +getallen en een exponent, en dat heb ik allemaal niet nodig. +Ten tweede...hmm, ik weet geen tweede reden te verzinnen, +maar de reden die ik opgaf was voor mij al genoeg om de MP +maar niet te gebruiken. + +Goed, BCD-getallen dus. BCD wil niets anders zeggen dan +Binary Coded Decimal. In gewoon Nederlands houdt dit in dat +je met 4 bits ��n getal aangeeft en dat betekent dat je met +1 byte 2 getallen kunt weergeven. Een klein voorbeeldje om +alles te illustreren: + +9 is en blijft negen. +19 wordt &b0001 1001 = &h19 +52 wordt &b0101 0010 = &h52 + +Okee, dit lijkt me nu wel duidelijk. Nu is een notatie +natuurlijk niet genoeg om de getallen te kunnen gebruiken, +want zonder correctie zou bijvoorbeeld 19 (=&h19) + 52 +(=&h52) 107 (=&h6b) worden en dat is dus niet goed, want het +goed antwoord zou &h71 moeten zijn. Bij aftrekken gaat het +ook fout (&h52 - &h19 = &h39, het goede antwoord is echter +&h33). + +Gelukkig kent de Z80 een hele handige instructie om het +resultaat te corrigeren, namelijk DAA. Dit betekent Decimal +Adjust Accumulator. Deze instructie test eerst op de H-flag +(bit 4). Als deze geset is (zoals bij ons het geval was), +dan moet het getal gecorrigeerd worden en anders natuurlijk +niet. + +Als er een getal gecorrigeerd moet worden, kijkt de Z80 naar +de N-flag (bit 1). Deze flag geeft aan of er een aftrekking +of een optelling plaats vond. Let op: deze instructie werkt +alleen als er ADD of SUB gebruikt werd. Als er een getal +afgetrokken werd, moet register A met 6 verlaagd worden en +anders juist met 6 verhoogd worden. Tot slot wordt de Carry- +flag geset als het resultaat niet in een BCD-getal past (b.v. +99 (&h99) + 2 (&h02) = 101 (&h01). Hier wordt de carry dus +geset). + +Met deze informatie zou je zelf een optel/aftrek-routine +kunnen maken voor BCD-getallen. Een kleine tip: reken van +achter naar voren en gebruik ADC/SBC om te rekenen. Mocht je +er niet uitkomen, lees deze tekst dan nog eens of kijk eens +in de file CALC.GEN (staat op deze FD) en dan zal het wel +duidelijk zijn. + + + RLD/RRD + +Voor het vermenigvuldigen/delen van BCD-getallen is het +handig om getallen ��n plek naar links of naar rechts op te +kunnen schuiven. Hiervoor heeft de Z80 ook instructies, +namelijk RLD en RRD. Het gebruik hiervan is ietwat lastiger +dan bij gewone schuifinstructies, maar echt lastig is het +ook weer niet. + +De instructies RLD/RRD verschuiven getallen via register A +en het getal op adres HL, waarbij RLD natuurlijk naar links +schuift en RRD naar rechts. De werking van de instructies +blijkt uit het volgende schemaatje: + +RLD: + >--->--->--->---> + ! ! + &b0000 0000 &b0000 0000 + ! ! ! ! + <---<---<--- <--- + reg A (HL) + +RRD + <---<---<---<---< + ! ! + &b0000 0000 &b0000 0000 + ! ! ! ! + --->--->---> ---> + reg A (HL) + +Om alles nog wat duidelijker te maken, komen hier nog twee +voorbeeldjes: + +RLD: +A: &h04 +HL: &hC000 +(HL): &h59 + +Na afloop van de instructie RLD is het resultaat: + +A: &h05 +HL: &hC000 +(HL): &h94 + +RRD: +A: &h04 +HL: &hC000 +(HL): &h59 + +Na afloop van de instructie RRD is het resultaat: + +A: &h09 +HL: &hC000 +(HL): &h45 + +Volgens mij moeten jullie nu ook wel in staat zijn om een +vermenigvuldigings-routine te programmeren. Als het toch +niet lukt, kijk dan eventjes naar de routines in CALC.GEN +en dan zal alles (hoop ik) wel duidelijk zijn. + + +Arjan diff --git a/future_disk/40/assembly_cursus_8.md b/future_disk/40/assembly_cursus_8.md new file mode 100644 index 0000000..8833c29 --- /dev/null +++ b/future_disk/40/assembly_cursus_8.md @@ -0,0 +1,63 @@ +# ASSEMBLY (8) + + De vorige keer hebben jullie deze rubriek moeten missen + vanwege inspiratiegebrek, maar voor deze keer heb ik toch + iets weten te verzinnen, namelijk het gebruiken van extra + opties bij een DOS-programma (dus bv PRINT FD.TXT, waarbij + PRINT.COM een programma is om een tekst naar de printer te + sturen en FD.TXT de af te drukken tekst is). + + Het kunnen gebruiken van die extra optie is heel simpel. Op + adres #80 staat het aantal tekens dat na het commando werd + ingevoerd en op adres #81 en verder staat de ingevoerde + tekst. Het aantal tekens is overigens exclusief de byte #0d + (Carriage Return). Hier volgt een (heel simpel) voorbeeld- + programmaatje: +``` + org #0100 + + bdos: equ 5 + strout: equ 9 + + ld a,(#0080) ; aantal tekens + or a + jr z,notext ; 0 tekens = geen tekst + + ld e,a ; aantal bytes + ld d,0 + ld hl,#0081 + add hl,de ; pointer naar einde tekst+1 + ld a,"$" + ld (hl),a ; vervang #0d door "$" + + ld de,#0081 + ld c,strout + call bdos ; print string + ret + + ;geen tekst ingevoerd + notext: ld de,text + ld c,strout + call bdos ; print tekstje + ret + + text: defb "No text entered$" +``` + Dit programmaatje staat ook op disk, zowel de source als de + geassembleerde file, welke ASSEMB8.GEN en ASSEMB8.COM heten. + + +## CACHE-ROUTINES + + Ongeveer een jaar geleden heb ik voor de FD eens een cache- + routine geschreven. Deze is echter nooit gebruikt, voor- + namelijk omdat de MoonSound-replayer erg veel ruimte + gebruikt. De volgende keer zal ik deze cache-routine's + bespreken, want daar heb ik nu vanwege de toch wel krappe + deadline echt geen tijd voor. Voor de liefhebbers staat de + source wel op disk (CACHE.GEN). Oh ja, deze cache-routine + cached alleen sectoren, geen files. Misschien maak ik voor + de volgende keer ook nog een cache-routine voor files, maar + dat zien jullie dan wel. + +Arjan diff --git a/future_disk/40/schuiven_en_roteren.md b/future_disk/40/schuiven_en_roteren.md new file mode 100644 index 0000000..3e00875 --- /dev/null +++ b/future_disk/40/schuiven_en_roteren.md @@ -0,0 +1,131 @@ +# SCHUIVEN & ROTEREN + + De moeilijkste commando's die de Z80 kent, zijn wat mij + betreft wel de schuif- en roteerinstructies, en dan wel met + name het gedoe rond het gebruik van de carry-flag. Zelfs + mijn MSX Machinetaalboek (Dullin/Strassenburg) gaat op dit + gebied de mist in. Gelukkig staan daar ook copi◊n van de + Z80-tabellen in, waar alles uiteraard correct instaat, dus + dat maakt het wel weer goed, maar lastig blijven de + instructies wel. + + De schuifinstructies zijn overigens wel makkelijk, maar + omdat schuif-instructies dicht bij roteerinstructies zitten, + neem ik ze hier toch maar mee. De instructies RLD en RRD + laat ik hier buiten beschouwing. Op een vorige FD (38 geloof + ik) is hier meer informatie over te vinden. + + +## SCHUIVEN MAAR + + Er zijn 3 verschillende (offici◊le) soorten schuifinstruc- + ties, namelijk SLA, SRA en SRL. Deze instructies kunnen als + parameter meekrijgen: een register (A,B,C,D,E,H,L) of een + pointer ( (HL),(IX+d),(IY+d) ). + + De instructie SLA is te vergelijken met een vermenigvuldi- + ging van 2. De bits worden rekenkundig (de letter A van SLA) + ÇÇn plaatsje naar links (de letter L) geschoven (de letter + S), waarbij bit 0 nul wordt en de oorspronkelijke bit 7 in + de carry-flag komt. + + De instructie SRA en SRL doen allebei ongeveer hetzelfde: + delen door 2. De bits worden ÇÇn plaatsje naar rechts + geschoven en bit 0 komt in de carry-flag terecht. Het + verschil tussen SRA en SRL is dat bij SRA bit 7 gelijk + blijft (zodat signed getallen correct gedeeld worden), + terwijl bij SRL bit 7 nul wordt. + + +## ROTEER ZE + + Het hele probleem van de roteer-instructies wordt veroor- + zaakt door de naamgeving van de instructies. Volgens mijn + logica zou de instructie RLCA de bits van register A naar + links schuiven, waarbij bit 7 in de carry-flag terecht komt + en de oude carry-flag in bit 0 komt. Het zou dus eigenlijk + ee soort 9-bits rotatie opleveren. Dit is echter niet het + geval. RLCA schuift de bits wel ÇÇn positie naar links, en + bit 7 komt ook wel in de carry-flag terecht, maar in plaats + van dat de oude carry-flag in bit 0 terecht komt, komt bit 7 + terecht in bit 0! Een voorbeeldje om alles duidelijk te + maken: + + Register A bevat de waarde &B01000001 ofwel 65 en de carry- + flag is gezet. Na een RLCA instructie wordt register A + &b10000010 (bit 0 wordt 0 omdat bit 7 nul was) en de + carry-flag wordt gereset (bit 7 was immers gereset). + + De instructie RLA daarentegen zou volgens mijn logica de + bits ook ÇÇn positie naar rechts schuiven, waarbij bit 7 in + de carry-flag terecht komt en bit 0 gelijk aan de oude bit 7 + wordt. Dit is echter niet het geval, want bij RLA wordt bit + 0 niet gelijk aan de oude bit 7, maar gelijk aan de oude + carry-flag! Weer even een voorbeeldje om alles duidelijk te + maken: + + Register A bevat de waarde &b01000001 ofwel 65 en de carry- + flag is gezet. Na een RLA instructie wordt register A + &b10000011 (bit 0 wordt 1 omdat de carry-flag gezet was) en + de carry-flag wordt gereset (omdat bit 7 oorspronkelijk + gereset was). + + Helemaal onlogisch is de naamgeving niet. De letter C uit de + instructie RLCA staat namelijk voor Circular (rondgaand in + het Nederlands), waarmee de makers proberen duidelijk te + maken dat de bits in hetzelfde register blijven. Wat mij + betreft is dit w◊l onlogisch, aangezien de instructie RLA + ook circulair is, alleen duurt het daar een ronde voordat + een oorspronkelijk bit weer terugkomt (na 9 keer RLA bevat + de accumulator weer de oorspronkelijke waarde, terwijl dit + bij RLCA na 8 keer al het geval is). + + De namen van de instructies zouden eigenlijk omgewisseld + moeten worden, waarbij de letter C de betekenis 'with Carry- + flag' ofwel 'met Carry-flag' zou moeten krijgen. De makers + van de R800 zagen dit ook in, daar heet de Z80-instructie + RLCA (die RLA zou moeten heten) ROLA (zonder C dus) en de + instructie RLA heet ROLCA, zoals het volgens mijn logica ook + zou moeten zijn (afgezien van die extra 'O' dan). + + Er zijn overigens wel meer instructies van naam verandert + bij de R800. Wat te denken van ROL4 (HL) in plaats van RLD, + of, nog leuker, MOVEM (HL++),(DE++) in plaats van LDIR. Maar + nu dwaal ik af geloof ik. + + Terug naar de roteerinstructies. Afgezien van het gedoe rond + die carry-flag, hebben de instructies wel een logische naam. + De eerste letter, R, staat voor Rotate. De tweede letter kan + een R of een L zijn. R betekent Right en L betekent dus + Left, om aan te geven welke richting de bits geschoven + moeten worden. Tot slot KAN er de letter C volgen. Als deze + er staat, betekent het (onlogisch) dat de carry-flag NIET + naar bit 0 getransporteerd wordt, zonder de letter C gebeurt + het (ook weer onlogisch) w◊l. + + De roteer-instructies kunnen dezelfde parameters krijgen als + de schuif-instructies, dus daar maak ik geen woorden meer + aan vuil. + + +## RLCA = RLC A??? + + Van de instructies die met de accumulator werken, bestaan er + twee versies, namelijk: +``` + RLCA en RLC A + RLA en RL A + RRCA en RRC A + RRA en RR A +``` + Het is een misverstand om te denken dat de instructies uit + de linker kolom hetzelfde doen als de instructies uit de + rechter kolom. De meeste programmeurs weten wel dat de + instructies uit de linker kolom een byte korter en twee keer + zo snel zijn, maar dat de flag-be◊nvloeding anders is weet + bijna niemand. Bij de instructies RLCA/RLA/RRCA en RRA + worden de zero-flag, de P/V-flag en de Sign-flag namelijk + niet be◊nvloed, terwijl dit bij de langere versies van deze + instructies wel het geval is. Let hier dus goed op!!! + +Arjan \ No newline at end of file diff --git a/Future Disk/42/Lijntjes.md b/future_disk/42/Lijntjes.md similarity index 100% rename from Future Disk/42/Lijntjes.md rename to future_disk/42/Lijntjes.md diff --git a/future_disk/42/assembly_cursus_9.md b/future_disk/42/assembly_cursus_9.md new file mode 100644 index 0000000..171b885 --- /dev/null +++ b/future_disk/42/assembly_cursus_9.md @@ -0,0 +1,453 @@ +Leest iemand dit? + + ASSEMBLY CURSUS 9 (1) + + + + OEPS OEPS OEPS... + + ...en nog eens oeps. Vorige keer stond in deze cursus dat er + een source van een cache-routine op disk zou staan. Dat was + helaas niet geval. Als het goed is, staat het dingetje nu + w�l op deze FD, en wel onder de naam CACHE.GEN. + + Vorige keer had ik ook beloofd om die cache-routine te + bespreken. Aangezien belofte schuld maakt, doe ik dat nu dan + maar ook. De routine in kwestie kan alleen sectoren cachen, + dus geen files. Daar had ik namelijk geen zin in, maar + misschien komt het er ooit nog eens van. Misschien ook + niet... + + + KESJING + + Caching is niets anders dan bepaalde informatie in het + geheugen op te slaan. In het geval van MSX betekent dat + bepaalde informatie maar ��n keer vanaf diskette ingeladen + hoeft te worden, mits er natuurlijk genoeg geheugen aanwezig + is (meestal meer dan 128 kB). Ik zal eerst maar eens globaal + uitleggen hoe de cache-routine die op deze FD staat werkt. + + Ergens in het geheugen staat een tabel van 2880 (1440 + sectoren * 2 bytes). Elk byte-paar geeft aan waar een sector + in het geheugen staat. Als beide bytes 0 zijn, dan staat de + sector nog niet in het geheugen, anders wel. De eerste byte + geeft aan in welke mapper-page de sector staat, de tweede + byte geeft aan op welk adres (#4000-#7fff) de sector staat. + Let op: dit byte is alleen de hi-byte! Deze opzet is vooral + handig als een hele diskette gecached moet kunnen worden. + Het is namelijk het makkelijkst en het snelst. + + De routine gebruikt dus 2 bytes voor het opslaan van de plek + waar de gecachde sector staat, namelijk ��n voor de + mapper-page en ��n voor het adres. Na elke gecachde sector + wordt het adres met 512 verhoogd, maar aangezien de + adres-pointer alleen de hi-byte bijhoudt, wordt deze met 2 + verhoogd (2*256=512). Zodra het adres boven #8000 uitkomt, + wordt deze teruggezet op #4000 en wordt de mapper-page met + ��n verhoogd. + + Nu ga ik verder met de source. Tussen de source door zal ik + af en toe wat extra informatie geven. + + Eerst eventjes wat constanten... + + bdos: equ #f37d + enaslt: equ #0024 + + setdta: equ 26 + diskrd: equ 47 + + minimum_pages: equ 9 + first_page: equ 8 + + De eerste 4 equ's hebben geen commentaar nodig, lijkt me. De + waarde minimum_pages geeft aan hoeveel pages van 16kB er + nodig zijn om de cache-routine te kunnen gebruiken. Het + geheugen moet trouwens in ��n slot zitten (daar wordt de + routine namelijk simpel van). In dit geval zijn er 9 blokken + van 16 kB nodig, dus een geheugen van 144kB of meer is + vereist. De waarde first_page geeft aan welke mapper-page + als eerste gebruikt wordt de cache-routine. Ik ga verder met + de source. + + init: jp init_cache + read: jp read_sectors + + Dit zijn de entries voor het gebruik van de cache-routine. + De routine 'init' initialiseert de cache-routines en 'read' + wordt gebruikt om sectoren te lezen (vanaf diskette of + vanuit RAM). Ik ga weer verder. + + init_cache: call count_map ;count number of pages + cp minimum_pages ;enough memory + jr c,no_cache ;no? -> no caching possible + + Eerst wordt de routine 'count_map' aangeroepen om te kijken + hoeveel geheugen er aanwezig is. Het aantal blokken wordt in + de accumulator gezet. Vervolgens wordt gekeken of er wel + genoeg geheugen is om caching toe te passen. Als er te + weinig geheugen aanwezig is, dan wordt er gesprongen naar de + routine 'no_cache'. Nog meer source... + + ld (number_pages),a ; store number of + available pages + + ld a,first_page ;first page to put + sectors in + ld (next_page),a + ld a,#40 ;first address of + cached sectors + ld (next_address),a + + ld hl,cache_table + ld de,cache_table + 1 + ld bc,1440 * 2 - 1 + ld (hl),0 + ldir ; clear cache-table + ret + + Het aantal aanwezige mapper-pages wordt opgeslagen, de + geheugen-pointers worden ge�nitialiseerd en de cache-table + wordt geleegd. + + ; no caching possible + no_cache: ld hl,read_disk1 + ld (read + 1),hl + ret + + De entry 'read' wordt omgebogen, zodat een aanroep meteen + tot diskactie leidt. Caching was immers niet mogelijk... + + ; Count number of pages in memory mapper + ; Out: A: number of pages + count_map: in a,(#fe) + push af + call store_old + call check_map + call restore_old + pop af + out (#fe),a + ld a,d + or a + ret nz + dec a + ret + + Deze routine kijkt hoeveel geheugen er in de primaire mapper + zit. 'store_old' bewaard alle bytes die zich op #8000 + bevinden, zodat er geen geheugen verloren gaat door het + onderzoeken van de mapper-grootte. 'check_map' telt het + aantal aanwezige mapper-pages. 'restore_old' herstelt het + geheugen weer en tot slot wordt er nog even gekeken of het + aantal mapper-pages 0 is (=256 = 4MB). Als dat zo is, dan + wordt het aantal pages gelijk aan 255 gemaakt (da's meer dan + genoeg). + + ; save old mapper data + store_old: ld bc,0 + ld hl,cache_table + + store_old_lp: ld a,c + out (#fe),a + ld a,(#8000) + ld (hl),a + xor a + ld (#8000),a + inc hl + inc c + djnz store_old_lp + ret + + Dit stukje code bewaard de originele geheugen-inhoud. Op + adres wordt de waarde 0 gezet, zodat later gezien kan worden + dat dit stukje geheugen nog niet geteld is. + + ; Count number of pages + ; Out: D: number of mapper pages + check_map: ld d,0 + + check_map_lp: ld a,d + out (#fe),a + + ld a,(#8000) + or a + ret nz + + dec a + ld (#8000),a + + inc d + jr check_map_lp + + Deze routine telt het aantal aanwezige mapper-pages. Als er + op adres #8000 een 0 staat, dan is de huidige page niet + meegeteld en kan het aantal pages met ��n verhoogd worden. + + ; Restore old mapper data + ; In: D: number of mapper-pages + restore_old: ld c,0 + ld b,d + ld hl,cache_table + + restore_old_lp:ld a,c + out (#fe),a + + ld a,(hl) + ld (#8000),a + + inc hl + inc c + djnz restore_old_lp + ret + + Hier wordt de oorspronkelijke geheugeninhoud weer hersteld. + +LEES VERDER IN DEEL 2! + + Leest iemand dit? Stuur dan een briefje of E-mailtje naar de redactie! + + ASSEMBLY CURSUS 9 (2) + + + We gaan vrolijk door waar we gebleven waren... + + ; Read sectors + ; In: L: drive (0=A, 1=B) + ; DE: first sector + ; H: number of sectors + ; BC: destinationaddress + read_sectors: push hl + + ld hl,cache_table + add hl,de + add hl,de + ld a,(hl) + or a ;already cached? + jp nz,read_cache + + Eerst wordt gekeken of de sector al gecached is. Als dat zo + is (A<>0) dan wordt naar de routine read_cache gesprongen + waar de sector vanuit RAM gelezen wordt. + + push bc + ld a,(number_pages) + ld b,a + ld a,(next_page) + cp b + pop bc + jr z,read_disk + + Hier wordt gekeken of er nog wel plek in het geheugen is om + de sector te cachen. Als dat niet zo is, wordt naar + 'read_disk' gesprongen waar de sectoren direct van diskette + worden gelezen. Let op: HL staat nog op de stack! Dit is zo + gedaan omdat HL nu nog eventjes nodig is. Lees maar eens + verder... + + ld (hl),a ; save current cache-page + + ld a,(next_address) + inc hl + ld (hl),a ; store hi-byte cache- + address + + De mapper-page en het adres waar de sector moet komen te + staan in het "cache-geheugen" worden opgeslagen. + + push bc + push de + ld d,b + ld e,c + ld c,setdta + call bdos ;set read address + pop de + pop bc + pop hl ; drive + number of sectors + back from stack + + Hier wordt het Disk Transfer Address goed gezet. + + push bc + push de + push hl + push bc ;destinationaddress + ld h,1 + ld c,diskrd + call bdos ;read 1 sector + + Een sector wordt ingelezen. + + in a,(#fd) + pop hl + push af + push hl + + ld a,(next_page) + out (#fd),a + + ld a,(#f342) + ld h,#40 + call enaslt + + Er wordt RAM geselecteerd op #4000-#7fff en de juiste page + wordt ingesteld. + + ld a,(next_address) + ld d,a + ld e,0 + pop hl ;Home Location + ld bc,512 + ldir ;move it to cache-memory + + De sector wordt naar het cache-geheugen verplaatst... + + ld a,(#fcc1) + ld h,#40 + call enaslt + + pop af + out (#fd),a + pop hl + pop de + pop bc + + call change_pointer ;change cache-pointer + + jp read_sectorslp ;repeat for next sector + + .. en de geheugeninstellingen worden weer hersteld. + Vervolgens wordt de routine change_pointer aangeroepen waar + het volgende adres voor de sector wordt veranderd en + eventueel de volgende pagina. Tot slot wordt gesprongen naar + read_sectorslp waar gekeken wordt of er nog meer sectoren + zijn om te lezen. + + change_pointer:ld a,(next_address) + inc a + inc a + ld (next_address),a ;next 512 bytes + cp #80 ;does it fit in the same page? + ret nz ;Yes -> finished here + ld a,#40 ;Begin of mapperpage (#4000) + ld (next_address),a + ld a,(next_page) + inc a + ld (next_page),a ;Next mapperpage for + caching + ret + + Het volgende adres in het cache-geheugen wordt berekend. Als + het adres #8000 wordt, wordt het adres weer op #4000 gezet + en wordt de volgende pagina met ��n verhoogd. + + ; read sector from disk + read_disk1: push hl ;number of sectors+drive has + to be pushed + read_disk: push de + + ld d,b + ld e,c + ld c,setdta + call bdos ;set read address + + pop de + pop hl ;number of sectors+drive back + from stack + ld c,diskrd + call bdos ;read rest of the sectors from + disk + ret + + Deze routine leest de resterende sectoren van diskette. Naar + read_disk1 wordt gesprongen als er bij het initialiseren van + de cache-routine's gebleken is dat er �berhaupt te weinig + geheugen voor caching is en naar read_disk wordt gesprongen + als er geen cache-geheugen meer over is. + + ; Move sector from cache-memory to destination address + ; In: HL: pointer to position-information + ; BC: destination address + ; DE: number of sectors + ; Note: number of sectors to be read and drive are pushed on the + ; stack (HL) + read_cache: push bc + push de + + push bc + push de + push hl + + ld a,(#f342) + ld h,#40 + call #24 + + pop hl + pop de + pop bc + + in a,(#fd) + push af + + ld a,(hl) + out (#fd),a + + Deze routine leest een sector vanuit het cache-geheugen. + Eerst wordt het juiste geheugen geschakeld.. + + inc hl + ld h,(hl) + ld l,0 + ld d,b + ld e,c + ld bc,512 + ldir + + ..vervolgens wordt de sector verplaatst.. + + ld a,(#fcc1) + ld h,#40 + call #24 + + pop af + out (#fd),a + + pop de + pop bc + pop hl + + ..en tot slot worden de geheugeninstellingen weer hersteld. + + read_sectorslp:dec h + ret z + + inc de + + inc b + inc b + jp read_sectors + + Het aantal sectoren wordt verlaagd, de te lezen sector wordt + verhoogd en het bestemmingsadres wordt met 512 verhoogd. + + number_pages: defb 0 + + next_page: defb 8 + next_address: defb #40 + + cache_table: defs 1440 * 2 + + Tot slot volgen het aantal ram-pages, de volgende pagina en + het volgende adres voor het cachen van sectoren en als + allerlaatste is er de tabel waarin staat of de sectoren + gecached zijn en waar ze dan gecached zijn. + + Nog een leuk nieuwtje: Smael gaat binnenkort proberen om een + cache-routine in de FD-routines te implementeren, als er nog + genoeg ruimte voor is. Ikzelf zie het nut er niet van in, + maar ja, als hij het zo graag wil...(NvdR: laat die jongen + toch, hij weet niet beter). Maar goed, het zit er weer op + voor deze keer. Tot de volgende FD! + + +Arjan diff --git a/Sunrise Special/1/R800.md b/sunrise_special/1/R800.md similarity index 100% rename from Sunrise Special/1/R800.md rename to sunrise_special/1/R800.md diff --git a/sunrise_special/1/disk_cursus_special_1.md b/sunrise_special/1/disk_cursus_special_1.md new file mode 100644 index 0000000..c7f76e0 --- /dev/null +++ b/sunrise_special/1/disk_cursus_special_1.md @@ -0,0 +1,647 @@ +# D I S K C U R S U S S P E C I A L ( 1 ) + + +## I N L E I D I N G + +In de diskcursus op Sunrise Magazine had ik al aangekondigd +dat er op de Sunrise Special een diskcursus voor gevorderden +zou komen. De cursus op het magazine is voornamelijk op +BASIC gericht, terwijl we hier juist de machinetaal aspecten +van het diskgebruik gaan bespreken. Ik ga er hier vanuit dat +de lezer een behoorlijke basiskennis heeft, ik zal dan ook +niet meer gaan uitleggen wat bijvoorbeeld een file is. + +Veel programmeurs vinden diskgebruik in machinetaal +moeilijk. Toch is het tamelijk eenvoudig, mits men in het +bezit is van duidelijke uitleg en documentatie. Elke MSX +computer met diskdrive heeft namelijk dezelfde serie BDOS +system calls tot zijn beschikking, waarmee vrijwel al het +werk uit handen wordt genomen. + +In deze cursus op de Special zullen (onder voorbehoud) de +volgende onderwerpen aan bod komen: + +- BDOS system calls +- BIOS calls (PHYDIO en FORMAT) +- Opbouw en werking bootsector +- Opbouw en werking FAT +- Opbouw en werking directory +- Zelf een programma schrijven dat vanuit de bootsector +opstart +- Zelf .COM files schrijven + +Dit is alles voor MSX-DOS 1/Disk BASIC 1.0. Misschien dat ik +aan het eind van de cursus verder ga met MSX-DOS 2/Disk +BASIC 2.01, maar dat is nu nog niet zeker. + +In dit eerste deel de werking van FAT en directory, oftewel +hoe staan files op een disk. + +## F A T + +Meteen al een ingewikkeld onderwerp: de File Allocation +Table. Bij het MSX Disk Operating System (kortweg MSX-DOS) +worden files behandeld als een verzameling clusters. Een +cluster bestaat bij een normale MSX disk (3.5") uit twee +sectoren. Een cluster is dus 2 * 512 = 1024 bytes (1 kB) +groot. + +Een file beslaat altijd minimaal ��n cluster, maar een file +die groter is dan ��n cluster worden over meerdere clusters +verdeeld. Dit betekent dat een file van slechts 1 byte op de +diskette toch maar liefst 1024 bytes in beslag neemt (1 +cluster), en een file van 2049 bytes 3 clusters (met in het +derde cluster slechts 1 byte). + +De FAT zorgt ervoor dat de ruimte op de disk altijd optimaal +wordt benut. Als er vaak op een diskette files worden +toegevoegd en andere files gewist, zullen de "volle" +clusters niet meer aaneengesloten op de disk staan. Zonder +de FAT zouden deze "gaten" niet meer kunnen worden benut. + +Als op een diskette waarop de vrije ruimte niet aan een +gesloten is een (grote) file wordt gezet, dan zullen eerst +de vrije ruimtes worden opgevuld, pas daarna wordt de vrije +ruimte "achteraan" benut. Zonder de FAT zou deze file later +nooit meer in te laden zijn, omdat het niet bekend is waar +de file verder gaat. In de FAT wordt dit bijgehouden. + +Stel u heeft de volgende files achter elkaar op een disk +staan: + +SUNRISE.001 cluster 2 t/m 4 +SUNRISE.002 cluster 5 t/m 6 +SUNRISE.003 cluster 7 t/m 10 + +Nu geeft u een KILL"SUNRISE.002" opdracht. De volgende +situatie ontstaat: + +SUNRISE.001 cluster 2 t/m 4 +vrij cluster 5 t/m 6 +SUNRISE.003 cluster 7 t/m 10 + +Nu zet u de file "SUNRISE.004" op de disk, die acht clusters +groot is. Nu gebeurt het volgende: + +SUNRISE.001 cluster 2 t/m 4 +SUNRISE.004 cluster 5 t/m 6 en 11 t/m 16 +SUNRISE.003 cluster 7 t/m 10 + +De file "SUNRISE.004" staat nu niet meer aaneengesloten op +de disk. Toch zal MSX-DOS de file zonder enig probleem +inlezen. En dat is waar de FAT om de hoek komt kijken. In +deze File Allocation Table (de naam zegt het al), wordt +namelijk opgeslagen waar (met welke cluster) een file verder +gaat. + + +## D E S T R U C T U U R + +De eerste byte van de FAT is de "FAT ID" byte. Dit is de +gewoon de "media ID", waarmee het formaat diskette wordt +aangegeven. Deze informatie staat ook in de bootsector, maar +het is natuurlijk makkelijk dat het ook in de FAT staat, +zodat de bootsector niet bij elke diskactie hoeft te worden +ingelezen. Bij MSX zijn de volgende twee ID's gebruikelijk: + +Naam: Aantal zijden: ID: + +MF-1DD 1 &HF8 +MF-2DD 2 &HF9 + +De volgende twee bytes van de fat zijn altijd &HFF en doen +niet ter zake. Op de vierde byte begint de eigenlijke tabel. +De informatie is opgeslagen in een vreemd formaat van 12 +bits per FAT entry. De eerste FAT entry is nummer 2. Het +nummer van de FAT entry is ook het nummer van de cluster die +ermee correspondeert. Een voorbeeld FAT in hexadecimaal: + +F9 FF FF 03 40 00 FF 6F 00 FF .F .. .. .. +0 1 2 3 4 5 6 7 8 9 10 11 +------- ------- -------- +entry entry entry +2 en 3 4 en 5 6 en 7 + +De bytes 0 t/m 2 bevatten de FAT ID (F9) en twee dummy bytes +(FF FF), het betreft hier een dubbelzijdige diskette. De +bytes 3 t/m 5 bevatten de informatie van cluster 2 en 3. Dit +moet als volgt worden gelezen: + +waarde cluster 2 = RECHTER nibble byte 4 + byte 3 = 003 +waarde cluster 3 = byte 5 + LINKER nibble byte 4 = 004 + +De waarde in een FAT entry wijst naar de cluster waarin de +file verder gaat. In FAT entry 2 staat "003", dus de file +gaat verder in cluster 3. In FAT entry 3 staat "004", dus de +file gaat verder in cluster 4. Zo eenvoudig is dat! + +Het einde van een file wordt aangegeven met "FFF". In fat +entry 4 staat "FFF", dus daar eindigt de file. De file staat +dus op cluster 2 t/m 4. We herhalen het stukje FAT nogmaals: + +F9 FF FF 03 40 00 FF 6F 00 FF .F .. .. .. +0 1 2 3 4 5 6 7 8 9 10 11 +------- ------- -------- +entry entry entry +2 en 3 4 en 5 6 en 7 + +We zien dat FAT entry 5 de waarde 006 bevat, de file gaat +dus verder met cluster 6. In FAT entry 6 staat FFF, dus daar +eindigt de file. Dit is dus een korte file, die slechts twee +clusters beslaat (5 en 6). + +Omdat de volgorde van de bytes nogal vreemd is zal ik nog +een duidelijk voorbeeld geven: + +21 43 65 + +Deze FAT entry's bevatten respectievelijk &H321 en &H654. + +Een leeg cluster wordt aangegeven met "000". Indien u een +bepaald gedeelte van een diskette wilt beschermen tegen de +BDOS (omdat u daar zelf de disk rechtstreeks op sector +niveau wilt lezen/schrijven), kunt u het overeenkomstige +deel van de FAT vullen met FFF. + + +## P L A A T S V A N D E F A T + +De FAT staat direct na de bootsector, en begint dus op +sector 1. Het aantal sectoren dat de FAT in beslag neemt is +afhankelijk van de grootte van de diskette. De grootte van +de FAT staat in de bootsector. Bij MSX-DOS wordt er direct +achter de FAT ook nog een kopie van de FAT bewaard. (In de +bootsector staat ook het aantal FATs vermeld.) Deze kopie is +nodig omdat de diskette niet meer normaal te gebruiken is +als de FAT niet meer in orde is. + +Rekent u even mee? Een dubbelzijdige diskette heeft 713 +clusters (7 clusters = 14 sectoren zijn nodig voor +bootsector (1), 2 FATs (6) en directory (7).) De FAT heeft +aan het begin ook nog twee clusters met de FAT-ID, dus in +totaal zijn er 715 FAT entry's. Elke entry vergt 12 bits, +dus er zijn 8.580 bits nodig. Een sector telt 4096 bits, dus +op een dubbelzijdige diskette neemt de FAT 3 sectoren in +beslag. De FAT staat dus op sector 1 t/m 3 en de reserve FAT +op sector 4 t/m 6. + +Bij een enkelzijdige diskette zijn twee sectoren +noodzakelijk, en staat de FAT dus op sector 1 en 2 en de +reserve FAT op sector 3 en 4. + + +## D I R E C T O R Y + +Met alleen de FAT kom je er niet. Je kunt een file immers +niet terugvinden zonder te weten waar hij begint (het nummer +van de eerste cluster). Dus staat er op een diskette direkt +achter de FAT (dubbelzijdig sector 7 t/m 13, enkelzijdig +sector 5 t/m 11) de directory (inhoudsopgave). In de +directory worden de volgende gegevens opgeslagen: + +- de filenaam +- de extensie +- de tijd +- de datum +- de lengte +- de eerste cluster + +De directory is 7 sectoren lang, dat is 3584 bytes. Elke +directory entry vergt 32 bytes, er passen dus 112 files op +een diskette. Maar dat wist u natuurlijk al. + + +## D E S T R U C T U U R + +Hoe is de directory opgebouwd? De 112 entry's staan achter +elkaar op de zeven sectoren. Elke entry is 32 bytes lang. +Deze bytes zijn als volgt ingedeeld: + ++0 Filenaam ++8 Extensie ++11 Attribuut ++12-21 Niet gebruikt (voor compatibility met MS-DOS) ++22 Tijd ++24 Datum ++26 Eerste cluster ++28 File lengte + +Voor de filenaam en de extensie verwijs ik u naar Disk +Cursus (1) op Sunrise Magazine #1. De Filenaam is maximaal 8 +karakters lang, de extensie maximaal 3 tekens. De punt staat +uiteraard niet in de directory. + +De attribuut wordt bij MSX-DOS1 eigenlijk niet gebruikt, +normaal staat daar een 0. Bij MSX-DOS2 (en MS-DOS) worden +hier de attributen (read only, hidden, etc.) bewaard. De +enige attribuut die door MSX-DOS1 wordt "ondersteund" is +"hidden", de file is dan helemaal niet meer in te lezen en +komt niet in de filelist voor als die wordt opgevraagd met +DIR of FILES. Onder MSX-DOS1 is de attribuut byte als volgt +opgebouwd: +``` +MSB 7 6 5 4 3 2 1 0 LSB + x x x x x x H x +``` +x: niet gebruikt +H: 1=hidden, 0=normaal + +De tijd is opgeslagen in twee bytes: +``` +MSB 7 6 5 4 3 2 1 0 LSB +U4 U3 U2 U1 U0 M5 M4 M3 Byte 23 +M2 M1 M0 S4 S3 S2 S1 S0 Byte 22 +``` +U0-U4: uren (0-23) +M5-M0: minuten (0-59) +S4-S0: secondes (0-29) + +Waarbij de secondes door 2 zijn gedeeld (om het goede getal +te krijgen moet de waarde die in S0-S4 is opgeslagen dus met +2 worden vermenigvuldigd). Let op de volgorde van de bytes! + +De datum is op soortgelijke wijze opgeslagen: +``` +MSB 7 6 5 4 3 2 1 0 LSB +J6 J5 J4 J3 J2 J1 J0 M3 Byte 25 +M2 M1 M0 D4 D3 D2 D1 D0 Byte 24 +``` +J0-J6: jaar (1980-2079, moet 1980 bij worden opgeteld) +M0-M3: maand (1-12) +D0-D4: dag (1-31) + +Let wederom op de volgorde van de bytes! + +De eerste cluster en de filelengte staan in normaal Z80 +formaat, dus de bytes in volgorde van low naar high: + +cluster = (byte 26) + 256 * (byte 27) +filelengte = (byte 28) + 256 * (byte 29) + 65536 * (byte 30) ++ 16777216 * (byte 31) + +Byte 31 van de filelengte zal bij een normale diskette niet +worden gebruikt, omdat de maximale lengte van een file (op +een dubbelzijdige diskette) 713 * 1024 = 730.112 bytes +bedraagt. Daarvoor zijn drie bytes (0-16.777.215, 16 MB) +ruimschoots voldoende. De vierde byte (waardoor waardes tot +256^4 mogelijk zijn, 4096 MB), wordt alleen bij harddisks +gebruikt. + +Als een nieuwe file op een disk wordt gezet, wordt daarvoor +de eerste de beste vrije directory entry gebruikt. Als een +file wordt gewist, wordt de eerste byte van de filenaam +vervangen door &HE5. Een 0 als eerste byte van de filenaam +geeft aan dat deze en alle volgende entry's nog nooit zijn +gebruikt en dus leeg zijn. + +Als de directory vol is, kunnen er geen nieuwe files meer op +de disk worden gezet. Ook niet als er nog bergen vrije +clusters zijn. Bij MSX-DOS2 is dit probleem opgelost door +subdirectories, maar bij DOS1 zullen we gewoon een nieuwe +disk moeten pakken of een paar oude files moeten killen. + +## E E N V O O R B E E L D + +Op deze Sunrise Special #1 staat het BASIC programma +"DIR.BAS". Dit programma past de eerder verworven kennis +toe. Dit programma geeft van een diskette een zeer volledige +directory, met de volgende gegevens: + +- de filenaam +- de tijd +- de datum +- de filelengte in bytes +- de filelengte in clusters (cls) +- een lijstje met alle clusters waarop de file staat in de +juiste volgorde + +De eerste vier worden ook door het DIR commando van MSX-DOS +gegeven, en daarvoor hoeft alleen de directory worden +uitgelezen. Maar voor het laatste moet de FAT worden +uitgeplozen. + +Ik heb het programma in BASIC geschreven omdat het dan +makkelijker is te volgen, bovendien zou ik bij machinetaal +dingen moeten gebruiken die we nu nog niet gehad hebben. +Hieronder volgt de listing, die ook in het softwaremenu te +vinden is. De listing wordt regelmatig onderbroken voor +uitleg. + + +## D I R . B A S +``` +1000 'DIR.BAS +1010 'Door Stefan Boer +1020 'Geeft dir met filenaam, tijd, datum, lengte, aantal +clusters en clusterverdeling van file +1030 'Voor Sunrise Special #1 - Bij Disk Cursus Special (1) +1040 '(c) SteveSoft/Stichting Sunrise 1992 +1050 ' +1060 CLEAR200,&HBFFF:DEFINTA-Z:DEFUSR=&H156 +``` +In regel 1060 wordt het gebied vanaf &HC000 tegen BASIC +beschremd, hier komen de FAT en de directory te staan. De +BIOS routine op adres &H156 wist de toetsenbordbuffer, met +DEFINTA-Z wordt bepaald dat alle variabelen integers zijn. +``` +1070 DEFFNA$(X)=RIGHT$("0"+MID$(STR$(X),2),2) +1080 KEYOFF:SCREEN0:WIDTH80:COLOR=(4,0,0,4):COLOR15,4,4 +1090 PRINT"Uitgebreide directory" +1100 PRINT"Door Stefan Boer" +1110 PRINT"Gepubliceerd op Sunrise Special #1" +1120 PRINT"(c) Stichting Sunrise 1992" +``` +In regel 170 wordt een functie gedefinieerd, die nodig is +voor een nette datum en tijd. De functie voegt waar nodig +"verloopnullen" toe, zodat je bijvoorbeeld 01/06/1992 +krijgt. +``` +1130 PRINT +1140 PRINT"Plaats een diskette...";:U=USR(0):I$=INPUT$(1) +1150 PRINT:PRINT:PRINT"Inlezen van FAT en directory..." +1160 POKE&HF351,0:POKE&HF352,&HC0:A$=DSKI$(0,1): +POKE&HF352,&HC2:A$=DSKI$(0,2) +``` +In regel 1160 worden de eerste twee sectoren van de FAT +gelezen en vanaf &HC000 in het RAM gezet. Door het commando +A$=DSKI$(drive,sector) komt er niets in de variabele A$ +terecht (dat kan ook niet, want een string kan maar 255 +tekens lang zijn, en geen 512). De inhoud van de sector +wordt in het geheugen geplaatst, en wel vanaf het adres dat +op locatie &HF351/&HF352 staat. Drive 0 betekent de default +drive. +``` +1170 IFPEEK(&HC000)=&HF9THENS=7:POKE&HF352,&HC4: +A$=DSKI$(0,3)ELSES=5 +1180 FORI=0TO6:POKE&HF352,&HC6+2*I:A$=DSKI$(0,S+I):NEXT +``` +In regel 1170 wordt de FAT ID byte gelezen. Hieraan is te +zien of de diskette enkelzijdig (&HF8) is, of dubbelzijdig +(&HF9). Is de diskette dubbelzijdig, dan bestaat de FAT uit +drie sectoren (de derde sector wordt ingeladen) en begint de +directory op sector 7 (S=7), bij een enkelzijdige diskette +bestaat de FAT uit twee sectoren (die reeds zijn ingelezen), +en begint de directory op sector 5 (S=5). + +In regel 1180 wordt de directory ingelezen, die 7 sectoren +lang is. De directory wordt vanaf &HC600 in het RAM gezet. +``` +1190 PRINT:PRINT"Filenaam: Datum: Tijd: Bytes: +Cls: Clusters:":PRINT +``` +"Cls" staat voor de lengte in clusters, "Bytes" voor de +lengte in bytes. Onder "Clusters:" komen de clusters waarop +de file staat in de juiste volgorde te staan. +``` +1200 FORAD=&HC600TO&HD3FFSTEP32 +1210 IFPEEK(AD)=0THENENDELSEIFPEEK(AD)=&HE5THEN1360 +``` +Regel 1200 doorloopt de complete directory in het RAM. Die +directory begint op &HC600 en is 3.5 kB lang. Een directory +entry is 32 bytes groot. In regel 1210 wordt gekeken of het +einde van de directory is bereikt (eerste byte van filenaam +is 0), zo ja, dan wordt het programma met END be�indigt. Is +de eerste byte &HE5, dan is de file gewist en wordt er +verder gegaan met de volgende file (op regel 1360 staat een +NEXT commando). + +1220 FORI=0TO7:PRINTCHR$(PEEK(AD+I));:NEXT +1230 IFPEEK(AD+8)=32THENPRINT" ";ELSEPRINT".";: +FORI=8TO10:PRINTCHR$(PEEK(AD+I));:NEXT:PRINT" "; + +Deze twee regels zetten de filenaam op het scherm. Regel +1230 zet alleen een punt op het scherm indien er een +extensie is. +``` +1240 PRINTFNA$(PEEK(AD+24)AND31);"/";FNA$((PEEK(AD+24) +AND224)\32+8*(PEEK(AD+25)AND1));"/";:PRINTUSING +"#### ";PEEK(AD+25)\2+1980; +``` +Regel 1240 zet de datum op het scherm, die in de bytes 24 en +25 van de directory entry staat. Met de ingewikkelde +formules worden de juiste bits uit de twee bytes gefilterd. +De dag staat bijvoorbeeld in bit 0 t/m 4 van byte 24. Met +een AND 31 (=&B11111) instruktie wordt de dag uit de byte +gehaald. Ter herinnering: +``` +MSB 7 6 5 4 3 2 1 0 LSB +J6 J5 J4 J3 J2 J1 J0 M3 Byte 25 +M2 M1 M0 D4 D3 D2 D1 D0 Byte 24 +``` +``` +1250 PRINTFNA$(PEEK(AD+23)\8);":";FNA$((PEEK(AD+23)AND7)*8+ +(PEEK(AD+22)AND224)\32);":";FNA$(2*(PEEK(AD+22)AND31)); +" "; +``` +Met de tijd gaat het net zo. Het schema van de tijd opslag +nog een keer: +``` +MSB 7 6 5 4 3 2 1 0 LSB +U4 U3 U2 U1 U0 M5 M4 M3 Byte 23 +M2 M1 M0 S4 S3 S2 S1 S0 Byte 22 +``` +``` +1260 L#=PEEK(AD+28)+256*PEEK(AD+29)+65536!*PEEK(AD+30): +PRINTUSING"###### ";L#; +``` +Hier wordt de lengte in bytes uit de directory gelezen en op +het scherm gezet. Eigenlijk moet ook AD+31 worden +uitgelezen, maar die wordt bij een diskette toch niet +gebruikt. Er moet een # achter de L, omdat een file groter +kan zijn dan 32767 bytes, en dan zou je zonder # een +"Overflow" foutmelding krijgen (vanwege de DEFINTA-Z). +``` +1270 PRINTUSING"### ";INT((L#+1023)/1024);:X=45 +``` +Hier wordt het aantal clusters dat de file in beslag neemt +berekend en op het scherm gezet. De berekening zou ook +als volgt kunnen worden gedaan: +``` +CL=INT(L#/1024):IFCL<>L#/1024THENCL=CL+1 +``` +Het resultaat is precies hetzelfde (CL is het aantal +clusters), maar ik vind de eerste manier veel mooier. +INT(L#/1024) is niet goed, omdat je dan bijna altijd 1 +cluster te weinig hebt (INT(1000/1024) is 0, maar een file +van 1000 bytes neemt ��n cluster in beslag). INT(L#/1024)+1 +is meestal goed, maar niet als L# een veelvoud van 1024 is +(zoals in de tweede oplossing duidelijk is te zien). +``` +1280 C=PEEK(AD+26)+256*PEEK(AD+27) +``` +Lees het nummer van de eerste cluster uit de directory. Dit +staat op byte 26 en 27. +``` +1290 FA=(CAND1022)*1.5+&HC000:PRINTTAB(X);: +PRINTUSING"###";C;:X=X+4:IFX=81THENX=45 +``` +In regel 1290 wordt het FAT adres (FA) berekend. C AND 1022 +zorgt dat C een even getal wordt, door er 1 vanaf te trekken +als het oneven was. Omdat twee FAT entry's samen 3 bytes in +beslag nemen, wordt dit vermenigvuldigd met 1.5. &HC000 is +het startadres van de FAT in het RAM. + +In X wordt de actuele X-coordinaat van de cursor +bijgehouden, zodat de clusternummers netjes rechts van de +overige informatie komen te staan. Het clusternummer wordt +op het scherm gezet met een PRINT USING, en de nieuwe X +coordinaat wordt berekend. +``` +1300 IFC<>(CAND1022)THEN1340 +``` +In deze regel wordt gekeken of we de eerste (even +clusternummer) of de tweede (oneven clusternummer) FAT entry +uit het groepje van 3 bytes moeten hebben. In regel 1310 +wordt de even gelezen, in regel 1340 de oneven. +``` +1310 V=C:C=(PEEK(FA+1)AND15)*256+PEEK(FA) +1320 IFC=&HFFFTHEN1370ELSEIFV<>C-1THENPRINTTAB(X-1);">"; +1330 GOTO1290 +``` +Hier wordt de even FAT entry gelezen. De 4 hoogste bits +staan op FA+1 en de 8 laagste bits op FA. Deze waarde wijst +naar de volgende cluster. Als de waarde gelijk is aan &HFFF +dan is het einde van de file bereikt, en wordt verder gegaan +met de volgende file (regel 1370). Anders wordt er +teruggegaan naar regel 1290, waar het nieuwe FAT adres wordt +berekend, het clusternummer wordt geprint en weer verder +wordt gegaan met het uitlezen van die FAT entry. In V wordt +het Vorige clusternummer bewaard, in regel 1320 wordt +gekeken of dat ��n lager is dan het zojuist berekende +clusternummer (als dat zo is, dan zijn het twee opeen +volgende clusters). Er wordt een > op het scherm gezet als +er een "gat" is. +``` +1340 V=C:C=((PEEK(FA+1)AND240)\16)+PEEK(FA+2)*16 +1350 IFC=&HFFFTHEN1370ELSEIFV<>C-1THENPRINTTAB(X-1);">"; +1360 GOTO1290 +``` +In regel 1340 t/m 1360 precies hetzelfde, alleen nu voor de +FAT entry met een oneven nummer. Hier staan de 4 laagste +bits op FA+1 en de 8 hoogste bits op FA+2. +``` +1370 IFPOS(0)>0THENPRINT +1380 NEXT +``` +Regel 1370 zorgt ervoor dat er op een nieuwe regel wordt +begonnen. Als er alleen PRINT zou hebben gestaan, zou er een +regel over worden geslagen als de cursor al op een nieuwe +regel stond. Regel 1380 zorgt dat er met de volgende +directory entry wordt verdergegaan. + + +## V O O R B E E L D U I T V O E R + +Laten we een eerder gebruikt voorbeeld nog eens nemen. Op +een disk staan de files: + +SUNRISE.001 cluster 2 t/m 4 +SUNRISE.004 cluster 5 t/m 6 en 11 t/m 16 +SUNRISE.003 cluster 7 t/m 10 + +DIR.BAS geeft dan de volgende uitvoer: + +Filenaam: Datum: Tijd: Bytes: Cls: Clusters: + +SUNRISE .001 22/06/1992 16:03:42 2404 3 2 3 4 +SUNRISE .004 24/06/1992 10:12:02 7169 8 5 6> 11 + 12 13 14 + 15 16 +SUNRISE .003 22/06/1992 16:10:16 3092 4 7 8 9 + 10 + +Het ">" tekentje geeft dus aan dat er een sprong wordt +gemaakt. Het kan soms voorkomen dat het programma de soep in +loopt. Dit ligt dan niet aan DIR.BAS (hoop ik), maar dan is +er waarschijnlijk iets mis met de FAT van die diskette. + +Gebruikt u DIR.BAS en ziet u veel > tekentjes, dan is het +verstandig om die diskette met een kopieerprogramma op +bestandsniveau (bijvoorbeeld BK of gewoon COPY onder +MSX-DOS) naar een andere (lege!) diskette te kopi�ren. De +bestanden worden dan weer netjes aangesloten achter elkaar +gezet. Bij het laden van een file betekent elk > tekentje +namelijk dat er een stuk van de disk moet worden +overgeslagen, en dit kost meestal extra tijd. Let op: +kopi�ren met een kopieerprogramma op sectorniveau (XCopy, +FastCopy, WorkMate, TurboCopy, etc.) heeft hier geen zin, +omdat de diskette dan letterlijk wordt overgenomen. + + +## B D O S + +Dit is behoorlijk ingewikkeld, maar gelukkig hoeft de +machinetaalprogrammeur zich normaal gesproken niet druk te +maken over FAT en directory. Als alle diskacties via de BDOS +worden afgehandeld (die in een volgend deel van de cursus +zeer uitgebreid zal worden besproken), dan zorgt de BDOS +ervoor dat de FAT en directory keurig worden bijgehouden. + +Toch is het handig om van deze informatie op de hoogte te +zijn. Het is bijvoorbeeld best te doen om een supersnel +laadsysteem te schrijven, waarbij de directory en de FAT in +het geheugen staan. Die hoeven dan niet steeds te worden +ingeladen, zodat de kop van de diskdrive minder op en neer +hoeft te gaan. Dit versnelt het laden van files aanzienlijk. +Dit systeem wordt toegepast bij BK, de BestandsKopieerder +voor MemMan van MCM's MST. + + +## W A A R S C H U W I N G ! ! + +Dit is een zeer belangrijke waarschuwing die ik ook nog wel +eens op Sunrise Magazine zal zetten. Stel er gebeurt het +volgende: + +U bent met een origineel programma bezig waarbij de diskette +waarop dat originele programma staat uiteraard op write +protected staat. Nu wilt u iets saven op een werkdisk, dus u +kiest de save optie. Maar per ongeluk laat u de disk van het +originele programma in de drive zitten, waardoor er een +write protected foutmelding volgt. U kunt kiezen uit Retry +of Abort. + +De logische oplossing lijkt nu om de werkdisk in de drive te +doen (write enable) en voor retry te kiezen. + +## D O E D I T N O O I T ! ! ! + +U kunt uw werkdisk daarna wel formatteren, want in ieder +geval de FAT en meestal ook de directory zal compleet +vernield zijn!!! + +Dit is een foutje van de BDOS, die in zo'n geval niet eerst +de FAT en directory van de nieuwe disk inlaadt, maar er +vanuit gaat dat alleen de write protect eraf is gehaald en +dat het nog steeds dezelfde diskette is. De BDOS maakt dus +de nodige wijzigingen in de FAT en directory die hij nog in +het RAM had staan en schrijft die dan naar de disk. Dat +waren dus de FAT en directory van de disk met het originele +programma, en die worden nu op uw werkdisk geschreven. U +begrijpt wel dat de informatie die op die werkdisk stond +alleen met zeer veel moeite of helemaal niet is terug te +halen. Kortom, kies in zo'n geval altijd voor abort en begin +opnieuw met het saven. Dan zal het wel goed gaan. + +Ik denk dat veel MSX'ers al eens een dergelijke ramp hebben +meegemaakt (bij mij is m'n disk met teksten al een stuk of +vijf keer op deze manier naar de haaien gegaan voordat ik +doorhad hoe het kwam), en niet wisten waar het aan lag. Nu +weet u het wel, en het kan u een hoop werk en ergernis +besparen! + +Oproep aan iedereen die software uitgeeft: waarschuw +hiervoor in de handleiding of maak een retry onmogelijk. (Ik +zal hier bij alle software die Sunrise uitgeeft persoonlijk +op letten!) + + +## T O T S L O T + +Ik denk dat ik er na deze afdwaling maar een eind aan draai. +Ik weet nu nog niet wat ik de volgende keer ga doen, maar +dat zou best wel eens de BDOS kunnen zijn. Dat zal een hele +lange tekst worden, want er zijn 42 BDOS calls! Tot de +volgende keer! + +Stefan Boer diff --git a/sunrise_special/1/geheugen_tellen.md b/sunrise_special/1/geheugen_tellen.md new file mode 100644 index 0000000..4b6bcba --- /dev/null +++ b/sunrise_special/1/geheugen_tellen.md @@ -0,0 +1,312 @@ +# G E H E U G E N T E L L E N + + +Niet elke MSX computer heeft dezelfde hoeveelheid RAM +geheugen. Vandaar dat het soms handig is om even te kijken +hoeveel geheugen er aanwezig is, zodat het lopende programma +daar rekening mee kan houden. + +Dit wordt bijvoorbeeld ook gedaan door de layoutroutine van +de Sunrise Special. Er wordt gekeken hoeveel RAM geheugen er +aanwezig is. Is dat 64 kB (het minimum op MSX2 en hoger), +dan moet elk MoonBlaster muziekje afzonderlijk worden +ingeladen. Is het meer, dan worden er zoveel mogelijk +MoonBlaster muziekjes in het geheugen gezet. Met 128 kB zal +er meestal al niet meer hoeven worden bijgeladen. + + +## A D D E R T J E + +Er zit echter een addertje onder het gras. Veel programmeurs +vinden het blijkbaar nogal moeilijk om zo'n routine te +schrijven. In demo's zit soms een hardwaretest, die ook +aangeeft hoeveel geheugen er aanwezig is. Ik heb het al heel +vaak meegemaakt dat zo'n routine veel te veel geheugen +opgeeft. Sommige demo's zeggen dat ik 2048 kB heb! Dat is +natuurlijk leuk, maar ik heb maar 256 kB dus heb ik er niets +aan als zo'n demo dat zegt. + + +## M E M O R Y M A P P E R + +De routine die ik geschreven heb, telt het RAM geheugen in +de huidige memorymapper dat op page 2 (&H8000-&HBFFF) is +geschakeld. De routine vindt dus niet AL het geheugen, +normaal gesproken alleen het geheugen van de grootste +mapper. Maar aangezien het gelijktijdig aansturen van +verschillende mappers een vervelende klus is, is het toch +niet zo erg. Ik raad u aan MemMan te gebruiken als u dat +toch van plan bent. + +Toch kan de routine wel gebruikt worden voor het tellen van +geheugen in verschillende mappers, er moet dan alleen een +routine omheen worden geschreven die alle sloten afgaat, +kijkt of er RAM in zit, ze op page 2 schakelt +(&H8000-&HBFFF) en vervolgens de telroutine aanroept. + +Dat schakelen van geheugen kan rechtstreeks gebeuren (met +I/O poort &HA8 en adres &HFFFF), of via de BIOS routine +ENASLT (&H0024). Misschien op de volgende Special de routine +die alle sloten afgaat. + +Bij het opstarten selecteert de MSX computer automatisch de +grootste mapper. Als in een Japanse MSX2+ met 64 kB dus een +externe mapper met 512 kB wordt gestoken, start de computer +vanuit die externe mapper op. Als u bijvoorbeeld een BASIC +programma laadt, dan komt dat in de externe mapper terecht. +Als u dus zonder eerst met het geheugen geknoeid te hebben +mijn routine gebruikt, zal altijd de grootte van de grootste +mapper worden bepaald. + + +## S L O T E N + +De plaats van het RAM in de computer is niet op alle +computers hetzelfde. Op de adressen &HF341 t/m &HF344 is per +page te vinden in welk slot het RAM zit: + +&HF341 page 0 &H0000-&H3FFF +&HF342 page 1 &H4000-&H7FFF +&HF343 page 2 &H8000-&HBFFF +&HF344 page 3 &HC000-&HFFFF + +De byte die op die adressen staat is een zogenaamde slot-ID +byte. Zo'n byte is als volgt opgebouwd: + +bit 7 6 5 4 3 2 1 0 + E 0 0 0 S1 S0 P1 P0 + +Bit 7 geeft aan of het slot geexpandeerd is of niet (1=ja). +Bits 2-3 geven het secundaire slotnummer (mits E=1). +Bits 0-1 geven het primaire slotnummer. + +De telroutine werkt vanuit page 2, dus daar moet de +memorymapper worden geschakeld. Normaal staat daar +natuurlijk al RAM, maar als dat niet zo is kan er op deze +manier RAM worden geschakeld: +``` + LD A,(&HF343) ; A=ID byte RAM page 2 + LD H,&H80 ; page 2 + CALL &H0024 ; ENASLT +``` +Voor de routine ENASLT moet de slot-ID byte in A staan, en +moet in HL een adres staan in de gewenste page. (Het is niet +nodig om LD HL,&H8000 te doen, want alleen de bovenste twee +bits van H worden hier gebruikt. Alle getallen tussen LD +H,&H80 en LD H,&HBF zijn dus geschikt.) U kan dit natuurlijk +ook zelf doen door met I/O poort &HA8 en adres &HFFFF aan de +gang te gaan, maar dat is veel ingewikkelder. Ik zal er hier +dan ook niet over uitweiden hoe dat in zijn werk gaat. + + +## S E G M E N T E N + +Er staat nu dus RAM op page 2. Dit RAM zit in een zogenaamde +memorymapper. Het RAM in een memorymapper is verdeeld in +blokken (soms wel 'maps' genoemd) van 16 kB. Ik noem deze +blokken verder segmenten. Per page is er een I/O poort +waarmee het segment van de memorymapper dat op die page +staat kan worden geselecteerd: + +page 0 &H0000-&H3FFF poort &HFC (3) +page 1 &H4000-&H7FFF poort &HFD (2) +page 2 &H8000-&HBFFF poort &HFE (1) +page 3 &HC000-&HFFFF poort &HFF (0) + +Tussen haakjes staan de standaardwaardes vermeld, zo is de +situatie als de computer is opgestart. Wees overigens niet +verbaasd als u andere waardes vindt bij het uitlezen van de +poorten, het gaat alleen om de geldige bits! + +Stel de computer heeft 64 kB, er zijn dan dus 4 segmenten +van 16 kB. Alleen de bits 0 en 1 van de vier poorten worden +dan gebruikt (zijn geldig), de overige 6 bits worden +genegeerd. (In twee bits kunnen namelijk vier verschillende +waardes worden gezet; 00, 01, 10 en 11.) + +Selecteer je bijvoorbeeld segment 9 op een computer met 128 +kB RAM (segmenten 0 t/m 7), dan wordt gewoon segment 1 +geselecteerd! (9 is &B1001, alleen de onderste drie bits +zijn geldig, &B001 is 1!) + +Een poort kan de waarde 0-255 bevatten, er kan totaal dus +256*16=4096 kB RAM in een memorymapper, oftewel 4 MB! + +Pas op met het gebruiken van segment 0, zoals je ziet staat +dit standaard op page 3, waar het systeem RAM staat. Zou je +dit segment ook op &HFE schakelen en het dan gebruiken, dan +zou het systeem RAM kunnen worden verminkt en slaat de +computer meestal vast. + +Voor poort &HFF geldt een zelfde waarschuwing, als je daar +een andere waarde naar schrijft moet je wel zorgen dat in +dat segment ook het systeem RAM staat, anders zal de +computer zeker hangen. + + +## T E L L E N + +Het bepalen van de grootte van de memorymapper is dus heel +simpel; gewoon het aantal segmenten tellen en dat +vermenigvuldigen met 16 kB. We gaan daarvoor alsvolgt te +werk: + +- We kiezen een adres uit wat zowel de routine als het + systeem RAM niet aantast +- We zetten in alle segmenten op dat adres een 0 +- We gaan nu alle segmenten langs en zetten daar een 255 als + we hem gehad hebben, zodat dubbel tellen uitgesloten is + +Deze procedure heeft een nadeel: na het doorlopen van de +routine is de inhoud van de memorymapper verminkt. Dit +kunnen we voorkomen door: + +- Aan het begin van de routine de waardes die op het gekozen + adres staan op te slaan in een buffer +- Aan het eind van de routine de waardes uit de buffer weer + terug te zetten + + +## D E S O U R C E + +Bovenstaande procedure is terug te vinden in de machinetaal- +routine die ik heb geschreven. Hier is de source, rijkelijk +voorzien van commentaar. + +``` +; M E M C O U N T . A S C +; Door Stefan Boer +; Deze routine telt het aantal aanwezige memorymaps +; op &H8000-&HBFFF +; Routine kan eventueel worden uitgebreid, zodat al het RAM +; wordt gevonden. +; 19/03/92, (c) SteveSoft 1992 +; Uitvoer: +; vanuit ML: A=hoogste memorymapper segment +; vanuit BASIC: U=USR(0) --> U=hoogste segment +; N.B. niet aantal segmenten, omdat 4 MB (256 segmenten) +; dan niet kan! + +; Enkele waardes + +ADRES: EQU &H81FF ; schrijft routine noch + ; systeem RAM over +MEMPRT: EQU &HFE ; I/O poort memorymapper + ; schakeling page 2 + + ORG &HC200 ; beginadres routine + +; Initialisatie + +MEMCNT: LD HL,ADRES ; HL check-adres + LD DE,BUFFER ; DE beginadres buffer + LD C,MEMPRT ; C I/O poort memorymapper + ; page 2 + IN A,(C) ; lees huidig segmentnummer + PUSH AF ; bewaar dit, wordt aan het + ; eind weer hersteld + +; Bewaar de huidige informatie die op +1FF staan +; N.B. Ik zeg +1FF in plaats van &H81FF omdat de segmenten +; geen vast beginadres hebben. Ze kunnen ook op 0000, +; 4000 of C000 staan. + + LD B,0 ; voer de lus 256 keer uit + ; (0 t/m 255) +SAVE: OUT (C),B ; schakel memorymapper + LD A,(HL) ; lees waarde +1FF + LD (DE),A ; zet waarde in buffer + INC DE ; volgende plaats in buffer + DJNZ SAVE ; doe dit met alle segmenten + ; (0 t/m 255) + +; Zet 0 op +1FF in alle segmenten + + LD B,0 ; voer de lus 256 keer uit + ; (0 t/m 255) + XOR A ; A=0 +ZERO: OUT (C),B ; schakel memorymapper + LD (HL),A ; zet 0 op +1FF + DJNZ ZERO ; doe dit met alle segmenten + ; (0 t/m 255) + +; Tel aantal werkelijk aanwezige segmenten + + LD D,0 ; D aantal gevonden segmenten + LD B,0 ; voer de lus 256 keer uit + ; (0 t/m 255) +CHECK: OUT (C),B ; schakel memorymapper + LD A,(HL) ; lees +1FF + CP &HFF ; al geteld? + JR Z,SLAOVR ; Ja, dan volgende segment + INC D ; aantal segmenten verhogen + LD (HL),&HFF ; segment gehad +SLAOVR: DJNZ CHECK ; doe dit met alle segmenten + ; (0 t/m 255) + PUSH DE ; bewaar aantal segmenten + +; Herstel de inhoud van +1FF van alle segmenten + + LD DE,BUFFER ; beginadres waar waardes + ; zijn opgeslagen + LD B,0 ; 256 segmenten (0 t/m 255) +RESTOR: OUT (C),B ; schakel memorymapper + LD A,(DE) ; lees waarde uit buffer + LD (HL),A ; zet waarde terug op oude + ; plaats + INC DE ; volgende plaats in buffer + DJNZ RESTOR ; doe dit met alle segmenten + ; (0 t/m 255) + +; Geef gevonden waarde door aan BASIC en ML en herstel +; originele stand van de memorymapper. + + POP DE ; D bevat aantal segmenten + POP AF ; haal oude waarde &HFE terug + OUT (C),A ; memorymapper page 2 weer + ; zoals bij begin + LD A,2 ; integer + LD (&HF663),A ; geef type variabele aan + ; BASIC door + LD A,D ; A bevat aantal segmenten + ; van 16 kB --> ML + DEC A ; met een verminderen + ; niet aantal maar hoogste! + LD L,A + LD H,0 ; LD HL,A + LD (&HF7F8),HL ; geef waarde aan BASIC door + RET ; einde routine + +BUFFER: DS 256 ; ruimte voor opslag +1FF + ; inhoud per segment +``` + +## O P D E D I S K + +Deze source is geschreven in WB-ASS2 en staat in ASCII op de +disk onder de naam "MEMCOUNT.ASC". Om de routine uit te +testen staat ook de file "MEMCOUNT.BIN" op deze Sunrise +Special #1. Deze file wordt geladen door "MEMCOUNT.BAS", dat +u in het softwaremenu kunt vinden. Dit programma laat zien +hoe u de routine vanuit BASIC kunt gebruiken. + + +## L E T O P + +U kunt deze routine normaal gesproken altijd gebruiken, +omdat hij het RAM niet blijvend aantast. Tijdens het lopen +van de routine wordt het RAM echter wel tijdelijke +aangetast. Het zou dus kunnen dat u een muziekje over de +interrupt laat lopen en dat dit programma in de driver zit +te POKEn en dan gaat het mis. De oplossing is simpel: +gewoon de interrupts uitzetten. Dus: +``` +DI +CALL MEMCNT +EI +``` +Misschien de volgende keer een uitbreiding waardoor de +routine meer dan ��n memorymapper aankan. Voor deze keer +laat ik het hierbij. + +Stefan Boer diff --git a/sunrise_special/1/het_rel_file_formaat.md b/sunrise_special/1/het_rel_file_formaat.md new file mode 100644 index 0000000..6b21be1 --- /dev/null +++ b/sunrise_special/1/het_rel_file_formaat.md @@ -0,0 +1,60 @@ +# H E T . R E L F I L E F O R M A A T + +Een GEN80 REL bevat informatie gecodeerd in een bit-stream +dat als volgt ingedeeld is. + +Als de eerste bit een 0 is dan zullen de volgende 8 bits in +het adres van de location counter geladen worden. + +Als de eerste bit een 1 is dan volgen er 2 bits met de +volgende betekenis. + +00 Het is een special link item die onder beschreven +wordt. +01 Program relative item, de volgende 16 bits zullen in +het adres van de location counter geladen worden +nadat ze zijn opgetelt bij het basis adres van het +programma/code segment. +10 Data relative item, de volgende 16 bits zullen in +het adres van de loaction counter geladen worden +nadat ze zijn opgeteld bij het basis adres van het +data segment. + +Een special link item bestaat uit het volgende: + +1 Een 4 bits lange control field, onder beschreven. +2 Een adres field dat een 2 bits adress type field is, +gevolgd door een 16 bits adres. Het adres type field +bestaat uit het volgende. + +00 Het adres is absoluut. +01 Het adres is relatief aan het programma. +10 Het adres is relatief aam het data segment. + +3 Een optioneel naam veld dat bestaat uit een 3 bits +lengte teller gevolgd door de naam van de label in 8 +bits ASCII. + + +## H E T C O N T R O L F I E L D + +De volgende link items worden gevolgd door een naam veld: + +0000 Deze label is PUBLIC verklaard in deze module. +0010 De naam van dit programma. + +De volgend link item worden gevolgd door een adres field. + +0111 Geeft de waarde in het adres field aan de label in +het naam veld. + +De volgende link items worden alleen gevolgd door een adres +field: + +1010 Define data size. Het adres veld bevat het totaal +aantal byte in het data segment van deze module +1011 Set location counter, veranderd het adres van de +location counter +1110 End of module. Geeft het einde van deze module aan +De volgende heeft geen velden +1111 End of file. Geeft het einde van de file aan diff --git a/sunrise_special/1/hybride_programmeren.md b/sunrise_special/1/hybride_programmeren.md new file mode 100644 index 0000000..6a2c533 --- /dev/null +++ b/sunrise_special/1/hybride_programmeren.md @@ -0,0 +1,647 @@ +# H Y B R I D E P R O G R A M M E R E N ( 1 ) + + +## I N L E I D I N G + +Dit is het eerste deel van een serie artikelen waarin ik wat +dieper in ga op het zogenaamde "Hybride programmeren", een +combinatie van BASIC en machinetaal. In de artikelen zal +vooral aandacht worden besteed aan de hulpmiddelen die de +MSX standaard biedt om de samenwerking beter te laten +verlopen, en waar men bij het hybride programmeren op moet +letten. + +Maar eerst zal ik uitleggen waar de naam hybride vandaan +komt. + + +## H Y B R I D E + +Het woord "hybride" komt zowel in de Nederlandse als in de +Engelse taal voor en betekent hetzelfde, namelijk het +resultaat van een kruising tussen twee verschillende +diersoorten. Bekende hybriden zijn muilezels, muildieren, +scheiten en gapen. Hybriden zijn altijd steriel, en bij het +fokken moeten afstotingsverschijnselen worden onderdrukt. +Maar genoeg biologie, terug naar MSX. + +Spreken we het woord op z'n Engels uit (haibraid), dan +bedoelen we er in de computerwereld iets anders mee: een +kruising tussen twee programmeertalen. Bij MSX is dat altijd +BASIC en machinetaal. Ik ga er in deze artikelen van uit dat +de lezer zowel BASIC als machinetaal in redelijke mate +beheerst. + + +## G R E N Z E N + +MSX BASIC heeft een werkgebied nodig voor het opslaan van +een BASIC programma en de daarbij behorende variabelen. Dit +werkgebied begint normaal gesproken op &H8000, maar dit kan +worden veranderd. Het adres waarop het BASIC programma +begint wordt opgeslagen op de volgende locatie: + +TXTTAB (&HF676, 2 bytes) Begin van "BASIC text area" + +Op (TXTTAB)-1 moet altijd een 0 staan. Normaal gesproken is +TXTTAB gevuld met de waarde &H8001, en bevat adres &H8000 +dus een 0. + +Na het veranderen van TXTTAB moet er een NEW worden gegeven, +zodat ook andere adressen (zoals het beginadres van de +variabelentabel) kunnen worden aangepast. Ditzelfde wordt +gedaan door een RUN"FILENAAM.BAS" of LOAD"FILENAAM.BAS" +instructie, er wordt dan door de BASIC interpreter eerst een +NEW uitgevoerd, en daarna wordt het BASIC programma geladen +en (bij RUN) ge�xecuteerd. U kunt dus na het veranderen van +TXTTAB ook een RUN"FILENAAM.BAS" of LOAD"FILENAAM.BAS" +commando geven. + +U kunt in BASIC het startadres van BASIC als volgt +veranderen: (veranderen naar &HC000) +``` +POKE&HF677,&HC0 +POKE&HF676,1 +POKE&HC000,0 +NEW +``` +Het kan ook vanuit een programma. Stel u wilt dat het +programma "EXAMPLE.BAS" op &HC000 staat. U kunt dat als +volgt programmeren: +``` +10 'EXAMPLE.BAS +20 IF PEEK(&HF677)<>&HC0 OR PEEK(&HF676)<>1 THEN +POKE&HF677,&HC0:POKE&HF676,1:POKE&HC000,0: +RUN"EXAMPLE.BAS" +30 ..... +``` +Vanaf regel 30 kunt u uw eigen programma invullen, save het +programma als "EXAMPLE.BAS". Wordt dit programma geladen +terwijl het adres al goed staat, dan wordt er direct verder +gegaan met regel 30. Anders wordt het adres goed gezet en +laadt het programma zichzelf nogmaals in, alleen nu op het +goede adres. + +Het gebied vanaf &H8000 tot (TXTTAB)-1 mag door machinetaal +worden gebruikt, hier kan BASIC nooit komen. + +Ook achter het BASIC programma is nog een gebied dat door +machinetaal gebruikt kan worden. Dit kan voor BASIC worden +beschermd met de CLEAR instructie. + + +## C L E A R + +Dit is een veelgebruikte (en meestal noodzakelijke) +instructie bij hybride programmeren. Eerst maar de syntax +van het CLEAR commando: + +CLEAR [][,] + +Voor de stringruimte moet een grootte in bytes voor het +datagebied voor strings worden ingevuld. Standaard is dit +200. Bij programma's die veel strings gebruiken is dat niet +genoeg, er volgt dan een "Out of string space" foutmelding. +Zo'n foutmelding kan worden voorkomen door de stringruimte +met het CLEAR commando te vergroten. Alleen een CLEAR +commando, dus zonder parameters, wist alle variabelen. + +Voor het adres moet het hoogste adres dat door BASIC mag +worden gebruikt worden ingevuld. Lees dit goed, het adres +zelf mag dus nog door BASIC worden gebruikt. Wilt u dus een +werkgeheugen voor machinetaal vanaf adres &HD000 reserveren, +dan moet het commando als volgt luiden: + +CLEAR 200,&HCFFF + +En niet CLEAR 200,&HD000, omdat dan de eerste byte van het +machinetaalgedeelte toch door BASIC kan worden veranderd. In +een hybride programma dat het gebied boven het BASIC +programma gebruikt moet ALTIJD een CLEAR commando worden +gezet! + +Met het CLEAR commando wordt de inhoud van HIMEM veranderd, +maar CLEAR doet nog veel meer. Zoals het wissen van alle +variabelen en het verplaatsen van een aantal werkgebieden. + +HIMEM (&HFC4A, 2 bytes) Bevat het hoogste adres dat door +BASIC mag worden gebruikt. + +De stack verhuist dan mee naar het gebied onder (HIMEM). +(Tussen haakjes betekent "de inhoud van".) Zoals u weet +groeit de stack aan de onderkant aan. De top van de stack +wordt ook in het systeem gebied opgeslagen: + +STKTOP (&HF674, 2 bytes) Bevat de top van de stack. + +Behalve de stack worden ook de File Control Blocks (niet die +van de BDOS, maar van Disk BASIC, 267 bytes per stuk, aantal +in te stellen met MAXFILES) verplaatst. + + +## D E B O V E N G R E N S + +De ondergrens van het machinetaalprogramma wordt dus door +het CLEAR commando bepaald. Maar wat is de bovengrens? + +Bij een MSX computer zonder diskdrive is dat erg eenvoudig. +Het systeemgebied van de MSX begint namelijk op adres +&HF380, dus het gebied tot &HF37F is vrij voor eigen +gebruik. + +Bij ��n of meer aangesloten diskdrives wordt de situatie +anders. De diskROM gebruikt namelijk een stuk geheugen onder +&HF380 als werkgeheugen, en de grootte van dat werkgebied +kan behoorlijk vari�ren. Dit is afhankelijk van het aantal +diskdrives en de grootte (enkelzijdig of dubbelzijdig) +daarvan. + +Meestal heeft een MSX2 computer 2 softwarematige drives, en +��n hardwarematige. Sommige luxe modellen hebben twee +hardwarematige drives (een hardwarematige drive is een echte +diskdrive, waar je een diskette in kunt steken, en een +softwarematige drive is een drive die door de diskROM wordt +ondersteund. Heeft een computer maar ��n hardwarematige +drive, dan zal de diskROM de softwarematige B: drive +simuleren met een "Insert diskette for drive B:" op de A: +drive). De tweede softwarematige drive kan worden +afgekoppeld door met de [CTRL] toets ingedrukt op te +starten. Hierdoor komt het werkgeheugen dat eerst voor de +softwarematige B: drive werd gebruikt vrij voor gebruik door +BASIC of machinetaal. + +Het maakt ook uit of de diskdrive enkelzijdig of +dubbelzijdig is. Er kunnen ook nog meer diskdrives actief +zijn, als er bijvoorbeeld een extra losse interface in een +cartridgeslot wordt gestoken. + +Tot slot speelt ook het actieve disk besturingssysteem een +rol. Bij Disk BASIC 1.0 (DOS1) is een veel groter werkgebied +nodig dan bij Disk BASIC 2.01 (DOS2). Kortom, u mag er nooit +vanuit gaan dat het werkgeheugen van de diskROM op elke +computer hetzelfde is. + +Waar mag u dan wel van uit gaan? Als u de computer opstart +bevat HIMEM altijd de juiste waarde. Het geheugen onder dat +adres wordt niet door de diskROM gebruikt, en kan dus veilig +voor machinetaal worden gebruikt. BASIC zorgt er zelf wel +voor dat het werkgeheugen van de diskROM niet wordt +overschreven. + +Lees direct na het opstarten dus HIMEM uit, en controleer of +uw machinetaal niet boven dat adres uit komt. Is dat toch +zo, geef dan een melding "Reset met [CTRL]" of iets +dergelijks, en stop de executie van het programma. Is er +niets aan de hand, dan kunt u rustig verder gaan met het +programma. Als zelfs het opstarten met [CTRL] niet helpt, +dan is kan het programma helemaal niet op die computer +worden gedraaid, in ieder geval niet in die configuratie. De +gebruiker kan dan bijvoorbeeld de C: en D: drive afkoppelen. + +Het is belangrijk om HIMEM uit te lezen voordat u een CLEAR +geeft, omdat CLEAR de waarde van HIMEM verandert. Het CLEAR +commando hoort trouwens vooraan het BASIC programma, omdat +het alle variabelen wist. + + +## V E I L I G E B O V E N G R E N S + +Bij bovenstaande methode moet er toch een bovengrens worden +gekozen. En het liefst een die op alle computers werkt, en +het liefst een waarbij niet met [CTRL] hoeft te worden +opgestart. Houd de bovengrens altijd zo laag mogelijk. +&HD7FF is een zeer veilige waarde, die met vrijwel geen +enkele configuratie problemen zal geven. + + +## S T A C K + +Houd wel rekening met de stack. In principe geeft die geen +problemen, maar als u eigenwijs toch geen CLEAR commando +gebruikt, dan staat de stack ergens een paar honderd bytes +onder de waarde van HIMEM bij het opstarten. + +Misschien is het even handig om de geheugenindeling onder +BASIC te geven: + +- BASIC programma +- Variabelen +- Arrays +- Vrij +- Stack +- Strings +- File Control Block +- Machinetaalprogramma +- Werkgebied Disk BASIC +- Werkgebied BIOS + + +## H I M E M O P S L A A N + +Als de besturing aan het eind van het programma weer +volledig aan BASIC wordt overgedragen, zorg dan dat HIMEM en +TXTTAB weer terug worden gezet. Zet TXTTAB daarbij op &H8001 +(vergeet niet de POKE &H8000,0) en zet HIMEM op de waarde +die er bij het opstarten in stond. Om dit te kunnen doen is +het nodig dat de waarde van HIMEM direct na het opstarten op +een veilige plaats wordt bewaard. + +We weten nu hoe we ervoor kunnen zorgen dat het BASIC +werkgebied, het machinetaal werkgebied, het BIOS/BASIC +werkgebied en het diskROM werkgebied elkaar niet storen, dus +we kunnen beginnen met het eigenlijke hybride programmeren. + +## U S R + +Bij hybride programmeren wordt het USR commando van BASIC +het meeste gebruikt. Met DEFUSR kunnen 10 machinetaal- +routines worden gedefinieerd. Dit gaat als volgt: + +DEFUSR= + +Waarbij voor een getal van 0 t/m 9 wordt ingevuld +(weglaten = 0) en voor het beginadres van de +machinetaalroutine. Voorbeeld: + +DEFUSR3=&HD000 + +De machinetaalroutine die op adres &HD000 begint kan nu +worden opgeroepen met USR3. De DEFUSR adressen worden in het +werkgebied opgeslagen in de tabel USRTAB, die begint op +adres &HF39A. Deze tabel bevat 10 adressen van 2 bytes per +stuk, en is dus 20 bytes lang. POKE &HF39A,0: POKE +&HF39B,&HC0 is dus hetzelfde als DEFUSR=&HC000. + +Het aanroepen van een machinetaalroutine gaat door het +opvragen van een waarde! Het USR commando is dus eigenlijk +een functie. Aan het USR commando kan ��n parameter worden +meegegeven. De syntax luidt als volgt: + +USR() + +Voor het moet weer een getal van 0-9 worden +ingevuld. De parameter kan niet worden weggelaten. Het USR +commando wordt als functie gebruikt. Een paar voorbeelden: +``` +U=USR(0) +PRINT USR3("HALLO") +A$=USR2(X$)+USR5(3) +PRINT USR6(3)*USR7("D") +P=3+USR(8.8354743) +X=LEN(USR9(5)) +``` +Als de waarde van USRx wordt opgevraagd, wordt naar het +adres dat met DEFUSRx is gedefinieerd gesprongen. De +parameter kan door het machinetaalprogramma worden +uitgelezen, en het machinetaalprogramma kan ook het +resultaat weer aan BASIC doorgeven. Dit is dus de "waarde +van USRx". Dit kan een getal zijn (INT, SNG of DBL), maar +ook een string. Hoe gaat dit doorgeven van parameters nu in +zijn werk? + +## D A T A U I T W I S S E L I N G + +Als een USR wordt aangeroepen springt de BASIC interpreter +niet meteen naar de machinetaalroutine, maar zal eerst een +aantal dingen doen. Een daarvan is het opslaan van de +parameter die tussen haakjes staat op een vaste plaats. + +Op VALTYP (&HF663) wordt het type variabele gezet. Hiervoor +gebruikt BASIC altijd dezelfde getallen, die overeenkomen +met de ruimte die de opslag van zo'n variabele in beslag +neemt (bij de stringvariabele is dat exclusief de string +zelf!). Een tabel: + +(VALTYP) Soort variabele: Voorbeelden: +------------------------------------------------------------ +2 integer (INT) A%, 32767 +3 string (STR) A$, "Sunrise" +4 enkele precisie (SNG) A!, 1.23456 +8 dubbele precisie (DBL) A#, 1.2345678901234 +------------------------------------------------------------ + +Deze waarde wordt bovendien in het A register geladen. Wilt +u bijvoorbeeld voordat u verdergaat met de rest van de +routine controleren of de parameter wel een integer is, dan +ziet dat er in ML zo uit: +``` + CP 2 ; parameter INT? + RET NZ ; nee, dan einde +``` +Het HL register bevat altijd de waarde &HF7F6, het +beginadres van DAC. Bij parameters van de typen INT, DBL en +SNG wordt de inhoud in DAC opgeslagen. Dit gaat als volgt: + +INT: DAC+2 bevat low byte + DAC+3 bevat high byte + +SNG: DAC+0 t/m DAC+3 bevatten getal in BCD formaat + +DBL: DAC+0 t/m DAC+7 bevatten getal in BCD formaat + +De behandeling van het BCD formaat valt buiten dit artikel. +Dit zal uitgebreid aan bod komen bij de behandeling van de +Math Pack (de rekenroutines van de BASIC interpreter). Dit +zal zeker op een komende Sunrise Special worden behandeld, +het is nu nog niet bekend op welke. + +Bij een string staat op adres &HF7F8 het adres waar de +zogenaamde "string descriptor" begint. Ditzelfde adres staat +ook in het DE register. De string descriptor ziet er als +volgt uit: + ++0 lengte van de string (0-255) ++1 low byte van beginadres van string ++2 high byte van beginadres van string + +Verderop in het artikel zullen een aantal voorbeeldlistings +volgen. Maar nu eerst het doorgeven van variabelen aan +BASIC. + +Als de machinetaalroutine geen variabele aan BASIC hoeft +terug te geven, dan kunt u de machinetaalroutine gewoon met +een RET be�ndigen. Anders moet voor de RET eerst DAC en +VALTYP met de juiste waarde worden gevuld. + +Zet de juiste waarde in VALTYP. Is het dezelfde soort +variabele als de parameter die werd doorgegeven, en heeft u +VALTYP in de routine niet veranderd, dan hoeft u dit +natuurlijk niet te doen. Door VALTYP te veranderen is +bijvoorbeeld zoiets mogelijk: + +A!=USR(B$) + +De waarden van de registers mogen allemaal worden veranderd. +A hoeft dus niet het type te bevatten en HL niet het +beginadres van DAC (en bij strings DE niet het beginadres +van de string descriptor), zoals bij de aanroep van een +routine door USR. BASIC kijkt daar namelijk helemaal niet +naar. Het vullen van HL en A (bij strings DE) met de juiste +waarden is alleen maar extra service van BASIC. + +Waar BASIC w�l naar kijkt is de inhoud van VALTYP en de +inhoud van DAC. Bij INT, DBL en SNG variabelen is het vullen +van DAC met de juiste waarde voldoende. Bij strings is er +echter een probleem. + + +## S T R I N G S + +Het doorgeven van een string aan een machinetaalroutine kan +erg handig zijn en geeft geen enkel probleem. Het doorgeven +van een string door een machinetaalroutine aan BASIC kan +echter wel grote problemen opleveren. + +De vraag daarbij is namelijk: waar moet die string in het +geheugen worden gezet? We gaan nu even uit van de situatie +A$=USR(B$). + +Als de resultaat-string even lang of korter is dan B$, en +als het niet erg is als de waarde van B$ verloren gaat, dan +is er geen probleem. Schrijf in de machinetaalroutine gewoon +het resultaat over de oude string heen, en klaar is Kees. +Indien nodig kan in de stringdescriptor de lengte worden +aangepast (alleen verkort!). + +Mag de string echter niet langer worden, of als B$ niet mag +worden overschreven, waar moet de resultaat-string (die door +BASIC aan A$ wordt doorgegeven) dan naartoe? + +Boven de CLEAR grens kan niet, omdat BASIC dan in de war +raakt. Strings mogen immers niet boven de CLEAR grens staan! +Ik heb deze manier zelf wel eens gebruikt, en bij mij werkte +het prima. Tot ik trots mijn programma ergens anders liet +zien, en de vreemdste teksten op het scherm werden getoverd. + +Het geheugen onder de CLEAR grens wordt door de BASIC +interpreter beheerd, je kan daar dus niet zomaar ergens een +string neer gaan zetten. De enige oplossing zou zijn om de +BASIC interpreter dit werk voor je te laten doen, maar +daarover heb ik onvoldoende documentatie. Gelukkig komt het +toch zelden voor dat je een machinetaalroutine wilt +schrijven waarbij het resultaat een string is. + + +## H O O F D L E T T E R S + +De eerste voorbeeld assemblerlisting zet van de string alle +kleine letters om in hoofdletters. Hier is de +assemblerlisting, regelmatig onderbroken voor uitleg. +``` +; C A P S . A S M +; Zet alle kleine letters in een string om in hoofdletters +; Door Stefan Boer, 2 juli 1992 +; (c) Stichting Sunrise 1992, Sunrise Special #1 + +FCERR: EQU &H475A ; BIOS error "Illegal + ; function call" + + ORG &HD000 + + CP 3 + JP NZ,FCERR ; error als geen string +``` +Register A bevat de soort variabele. Dit moet een string +zijn, met code 3. CP 3 vergelijkt A met de waarde 3. Is het +niet gelijk (NZ) dan volgt er een Illegal function call. +``` + LD A,(DE) + AND A + RET Z ; controle op lege string + LD B,A ; B=lengte + INC DE + LD A,(DE) + LD L,A + INC DE + LD A,(DE) + LD H,A ; HL=beginadres +``` +Hier wordt de stringdescriptor gelezen. De descriptor (= +"beschrijver") begint op het adres waar DE naar wijst. De +lengte van de string wordt in B gezet en het beginadres van +de string in HL. Als het een lege string is wordt er meteen +teruggesprongen naar BASIC. +``` +LOOP: LD A,(HL) + CP "a" + JR C,NEXT + CP "z"+1 + JR NC,NEXT + RES 5,A ; maak hoofdletter van + ; kleine letter + LD (HL),A +NEXT: INC HL + DJNZ LOOP ; herhaal voor hele string + + RET ; VALTYP en DAC hoeven niet + ; te worden veranderd +``` +Dit gedeelte zet de kleine letters om in hoofdletters. Eerst +wordt er gecontroleerd of het teken wel tussen a en z ligt. +Zo ja, dan wordt bit 5 gereset. Met een voorbeeld kunt u +zien hoe dat werkt. Een paar binaire ASCII codes: +``` +A &B01000001 +a &B01100001 +S &B01010011 +s &B01110011 + ^ + bit 5 +``` +Zoals u ziet bepaalt bit 5 of het een hoofd- of kleine +letter is (0=hoofd, 1=klein). + +De string wordt in dit voorbeeld gewoon overschreven. Stel u +heeft bovenstaande assemblerlisting geassembleerd, de +machinetaal staat dus op adres &HD000. Dan kunt u het +volgende BASIC programma uitvoeren: +``` +10 DEFUSR=&HD000 +20 A$="Sunrise" +30 B$=USR(A$) +``` +In dit geval bevatten zowel A$ als B$ na afloop "SUNRISE". +Mag de waarde van A$ niet verloren gaan, dan kunt u het +voorbeeld zo doen: +``` +10 DEFUSR=&HD000 +20 A$="Sunrise" +30 Q$=A$:B$=USR(Q$) +``` +Er gebeurt iets grappigs als u met een constante werkt: +``` +10 DEFUSR=&HD000 +20 U$=USR("Sunrise") +``` +Na het RUNnen van dit programma bevat de variabele U$ +uiteraard "SUNRISE". Typt u nu maar eens LIST in. Dit is wat +u dan te zien krijgt: +``` +10 DEFUSR=&HD000 +20 U$=USR("SUNRISE") +``` +Dus ook in het BASIC programma is de tekst in hoofdletters +omgezet. Dit komt omdat de BASIC interpreter de string +descriptor in dit geval gewoon naar de constante "Sunrise" +in het BASIC programma laat wijzen. + +U snapt nu wel dat het doorgeven van strings van machinetaal +aan BASIC nogal problematisch gaat. Andersom gaat het prima. + + +## T E K S T J E P R I N T E N + +Dit is een goed voorbeeld van een string doorgeven aan +machinetaal. Onderstaande assemblerlisting zet de string die +als parameter aan USR wordt doorgegeven op het scherm. +``` +; P R I N T S T R . A S M +; Print een string +; Door Stefan Boer, 2 juli 1992 +; (c) Stichting Sunrise 1992, Sunrise Special #1 + +FCERR: EQU &H475A ; BIOS error "Illegal + ; function call" + + ORG &HD000 + + CP 3 + JP NZ,FCERR ; error als geen string + + LD A,(DE) + AND A + RET Z ; lege string + LD B,A ; B=lengte + INC DE + LD A,(DE) + LD L,A + INC DE + LD A,(DE) + LD H,A ; HL=beginadres +``` +Dit gedeelte is bijna gelijk aan de vorige routine, het +haalt de stringdescriptor op. +``` +PRINT: LD A,(HL) ; haal teken + CALL &HA2 ; teken naar scherm + INC HL ; volgende teken + DJNZ PRINT ; herhaal B maal + + RET +``` +Dit gedeelte zet de string op het scherm, en gebruikt de +BIOS routine CHPUT (&HA2). De volgende routine bewijst dat +het doorgeven van getallen in beide richtingen geen enkel +probleem oplevert. + + +## R E K E N E N + +Onderstaande routine doet iets ontzettend moeilijks, hij +telt 1 op bij het getal dat als parameter aan USR wordt +meegegeven!!! Geweldig he?! +``` +; P L U S 1 . A S M +; Telt 1 op bij een getal +; Door Stefan Boer, 2 juli 1992 +; (c) Stichting Sunrise 1992, Sunrise Special #1 + +DAC: EQU &HF7F6 +ILLEGA: EQU &H475A + + ORG &HD000 + + CP 2 + JP NZ,ILLEGA ; Illegal function call als + ; geen integer + LD HL,(DAC+2) ; lees waarde + INC HL ; plus 1 + LD (DAC+2),HL ; geef waarde door aan BASIC + RET +``` +Deze routine behoeft geen uitleg meer, alle uitleg is al +eerder in dit artikel gegeven. Toch zit er hier wel een +addertje onder het gras. Typt u bijvoorbeeld: +``` +PRINT USR(3) +``` +Dan zet de computer netjes een 4 op het scherm. Typt u +echter: +``` +A=3 +PRINT USR(A) +``` +Dan volgt er een Illegal function call. Hoe kan dat? Dat +komt omdat alle variabelen (tenzij anders bepaald met een +DEF commando) automatisch van het DBL type zijn. Overal waar +A staat moet u dus A# lezen. En natuurlijk krijg je dan een +illegal function call, omdat VALTYP dan een 8 bevat in +plaats van een 2. Deze fout kan worden voorkomen door DEFINT +A te typen, of door achter elke A een % te plaatsen. +``` +DEFINT A +A=3 +PRINT USR(A) +``` +Dit werkt wel. Nog een laatste opmerking: alle registers +mogen worden veranderd door een routine die met USR wordt +aangeroepen (behalve natuurlijk SP, want dan kan er na +afloop niet meer worden teruggesprongen naar de BASIC +interpreter). + + +## T O T S L O T + +Dit lijkt me wel voldoende voor deze keer, de eerste manier +van samenwerking tussen BASIC en ML (USR) is nu volledig +besproken. De volgende keer komt het volgende BASIC commando +voor deze samenwerking aan bod: CMD. Ik heb al een leuke en +vooral handige voorbeeldroutine klaarliggen. + +Wie heeft er meer ervaring met het stringprobleem, en weet +wel een goede oplossing? Reacties graag naar de Sunrise +postbus, ter attentie van ondergetekende. Ik ben zelf al +bezig geweest met een oplossing, dus misschien kom ik daar +de volgende keer zelf mee op de proppen. + +Stefan Boer diff --git a/sunrise_special/1/memman_2.3_intro.md b/sunrise_special/1/memman_2.3_intro.md new file mode 100644 index 0000000..3d2ef7d --- /dev/null +++ b/sunrise_special/1/memman_2.3_intro.md @@ -0,0 +1,391 @@ +# M E M M A N 2 . 3 I N T R O D U C T I E + + +File : MM23INTRO.TXT c MST +Datum: 18 september 1991 +Door : Ries Vriend/Ramon van der Winkel/Robbert Wethmar + + + MST's MemMan 2, de MSX Memory Manager + +Begin 1990 riep MSX Computer Magazine voor het eerst de +beste MSX programmeurs van Nederland bij elkaar met de +bedoeling de MSX wereld nieuw leven in te blazen. De +programmeursgroep maakte kennis en er werden ideeen +uitgewisseld. Er bleek behoefte aan een Memory Manager, een +programma dat het geheugen van de MSX beheert. + +Met de Memory Manager worden twee doelen nagestreefd: + +1) Het zoeken en gebruiken van geheugen wordt eenvoudiger. +Het zoeken wordt door MemMan gedaan terwijl het gebruik +van geheugen zoveel mogelijk wordt losgekoppeld van de +configuratie: 'oude' uitbreidingen, een, twee of meer +mappers, MemMan heeft er geen moeite mee. +2) Het wordt mogelijk meerdere programma's tegelijkertijd in +het geheugen te laden zonder dat ze elkaar in de weg +zitten. Hierbij wordt gedacht aan RAMdisk's, +printerbuffers en op de achtergrond werkende programma's. + +Met versie 1 van MemMan - ge�ntroduceerd op 9 september 1990 +- is de eerste doelstelling bereikt. Nu is de tweede +doelstelling ook bereikt. + +MemMan versie 2 kan meerdere programma's 'ergens' in het +geheugen laden laten werken, zonder dat ze van elkaar last +hebben. Op andere computer merken was deze techniek al +langer bekend. Dergelijke programma's worden daar TSR's +genoemd, vandaar ook hier: Terminate and Stay Resident +programma's. + +Hopelijk zullen nog meer programma's van MemMan gebruik gaan +maken en bestaande programma's voor MemMan worden aangepast. +Een direct voordeel is dat het programma dan ook direct met +bijvoorbeeld 64 kB modules en zelfs met meerdere memory +mappers kan werken, iets dat de meeste bestaande programma's +niet of niet goed doen. + +MemMan versie 2 zal net als de eerste versie als Public +Domain de wereld in gestuurd worden. Dat wil zeggen dat +iedereen vrij van MemMan gebruik mag maken. Het is zelfs +toegestaan MemMan als onderdeel van een commercieel pakket +te verkopen. Alleen zo kan het programma uitgroeien tot een +aanvulling op de MSX standaard. Er zullen twee pakketten +uitgebracht worden. De eerst is voor de gebruiker van +MemMan. Dit pakket zal MemMan en een aantal tools voor de +TSR's bevatten. Het tweede pakket bevat ontwikkel tools en +technische documentatie over het programmeren van TSR's. Dit +laatste pakket is geen Public Domain. + + +Aan MemMan werkten en dachten mee: + +Ramon van der Winkel +Ries Vriend +Robbert Wethmar +Paul te Bokkel +Markus The +en een aantal anderen die met hun opbouwende kritiek MemMan +hielpen worden tot wat het is. + + + H E T C O N F I G U R E R E N + +MemMan is er in twee versies: een .BIN en een .COM file. Het +zal duidelijk zijn dat de .BIN versie vanuit BASIC met een +BLOAD"MEMMAN.BIN",R instructie geladen kan worden, terwijl +de .COM vanuit MSXDOS gestart kan worden door simpelweg +MEMMAN in te tikken. Beide versies keren na het laden - via +een zogenaamde warm boot - automatisch terug naar BASIC. Als +de .COM versie vanuit MSXDOS opgestart wordt, dan kan een +commandline mee gegeven worden. Dit zijn commando's welke +uitgevoerd zullen worden alsof ze ingetikt zijn. Een Return +kan met het @ teken worden opgegeven. Er kunnen meerdere @ +tekens in de commandline worden opgegeven, zodat meerdere +commando's na elkaar uitgevoerd kunnen worden. + +Bijvoorbeeld: + +A>MEMMAN _SYSTEM@TL CAPS@ + +Na het opstarten van MEMMAN zal naar MSXDOS teruggekeerd +worden en de TSR "CAPS" ingeladen worden. + +Met behulp van CFGMMAN is het mogelijk een aantal +instellingen van MemMan en een default commandline op te +geven. CFGMMAN kan zowel de .COM als de .BIN versie +configureren. Met betrekking tot de TSR's kunnen de volgende +instellingen veranderd worden: + +- Default command line +Hier kan de standaard commando-regel ingevoerd worden. Deze +commando-regel wordt uitgevoerd nadat MemMan ge�nstalleerd +is. Na het laden van de .BIN versie van MemMan wordt altijd +de standaard commando-regel uitgevoerd. De standaard +commando-regel wordt niet uitgevoerd indien MemMan vanuit +DOS opgestart wordt met een commando regel als argument. Na +foutmeldingen van MemMan wordt geen commando regel +uitgevoerd. + +- Heap grootte +Sommige TSR programma's hebben extra geheugen nodig in +geheugen pagina 3, waar ze normaal gesproken geen toegang +toe hebben. De heap is een stuk geheugen in pagina 3 dat wel +voor TSR's toegankelijk is. Wanneer een TSR meldt dat er te +weinig heap geheugen beschikbaar is dient deze waarde +verhoogd te worden. Meestal zal het toevoegen van 100 extra +bytes heap-geheugen de problemen uit de wereld helpen. +Wanneer een TSR meer heap-ruimte nodig heeft dient de +handleiding dat te vermelden. + +Elke verandering van de heap-grootte heeft slechts effect na +het opnieuw laden van MemMan. + +- Maximum aantal TSR's dat tegelijk aanwezig kan zijn +Het aantal TSR's dat onder MemMan 2 geladen kan worden is +beperkt. Wanneer de TSR Loader (TL) de melding 'TSR Table +Full' geeft dient deze waarde verhoogd te worden. + +- Maximum aantal hooks dat tegelijk afgebogen kan zijn +Het aantal hooks dat door alle in het geheugen aanwezige +TSR's kan worden afgebogen is beperkt. Wanneer de TSR Loader +de melding 'Hook Table Full' geeft dient deze waarde +verhoogd te worden. + +- Recursiediepte +Wanneer TSR's elkaar of zichzelf te vaak aanroepen zal het +systeem op een gegeven moment vastlopen. Door de maximale +recursiediepte te verhogen kunnen deze problemen voorkomen +worden. TSR's die zichzelf aanroepen dienen dat - met de +benodigde recursiediepte - te vermelden in de handleiding. + + + H E T I N S T A L L E R E N + +Om MemMem vanuit MSX-DOS te laden is het intikken van +`MEMMAN' achter de `>'-prompt voldoende. Vanuit BASIC dient +het commando BLOAD "MEMMAN.BIN",R ingevoerd te worden. Na de +installatie van MemMan wordt in beide gevallen BASIC +gestart, waarna de standaard commando regel uitgevoerd +wordt, zoals opgegeven in het configuratie programma +CFGMMAN. De standaard commando-regel wordt niet uitgevoerd +indien MemMan vanuit DOS gestart wordt met een vervangende +commando-regel als argument. + +Versie 2 van MemMan neemt behalve een stuk BASIC-geheugen +ook een 16 kB segment in beslag. Hierdoor blijft er onder +BASIC en MSXDOS zoveel mogelijk geheugen beschikbaar. De +ruimte die in het 16 kB segment over is wordt indien +mogelijk gebruikt om TSR's in onder te brengen. De +hoeveelheid BASIC-geheugen die MemMan gebruikt kan be�nvloed +worden door middel van het configuratieprogramma CFGMMAN. + +Wanneer MemMan onder DOS2 ge�nstalleerd wordt blijven alle +segmenten - behalve die ene die MemMan zelf nodig heeft - +ook voor DOS2 beschikbaar. Het is dus zonder meer mogelijk +eerst MemMan te installeren en daarna een DOS2 RAMdisk. + +Alvorens zichzelf in het RAM te nestelen controleert MemMan +natuurlijk of er al een versie van MemMan aanwezig is. In +dat laatste geval verschijnen de info-regels, aangevuld met +de mededeling dat MemMan reeds ge�nstalleerd is. Verder +gebeurt er niets. De commandoregel wordt gewoon uitgevoerd. + + + Terminate and Stay Resident programma's + +Gewoonlijk zal een programma na uitvoering niet in het +geheugen achterblijven. Programma's die dat wel doen worden +aangeduid met de afkorting TSR: Terminate and Stay Resident. +Voorbeelden van dergelijke programma's zijn: printerbuffers +en RAMdisks. Maar ook andere toepassingen, zoals een +rekenmachine of een kalender die met een enkele toetsdruk +opgeroepen kan worden zijn denkbaar. + +In het verleden zijn TSR's voor de MSX een tamelijk zeldzaam +verschijnsel geweest. Het probleem was namelijk dat het +geheugen dat de TSR gebruikt ook door andere programma's +gebruikt kan worden. Er zijn in een standaard MSX machine +geen mogelijkheden om een stuk geheugen voor een TSR te +reserveren. Dit probleem wordt door MemMan uit de wereld +geholpen. MemMan beheert het geheugen en zorgt er voor dat +er geen geheugenconflicten optreden. + +Dankzij MemMan is het mogelijk meerdere TSR's tegelijk in +het geheugen te hebben, waarbij elke TSR maximaal 16 kB +groot kan zijn. Op de standaard MSX is het laden van meer +dan ��n TSR al lastig en alleen mogelijk als de TSR niet al +te groot is. Met de invoering van MemMan 2 krijgt de MSX +betere TSR mogelijkheden dan de alom gewaardeerde PC. +Bovendien doen ze niet onder voor de `Desktop Accesoires' +zoals die op de Macintosh en de Atari ST gebruikt worden. + +Bij MemMan worden twee eenvoudige voorbeeld TSR's geleverd. +Ze doen weinig zinvols, maar demonstreren wel degelijk de +kracht vn Terminate and Stay Resident programma's. De +voorbeelden zijn CAPS.TSR en BEEP.TSR. De eerste laat het +Caps lampje knipperen, de tweede maakt dat het Basic +commando CMD BEEP een pieptoontje genereerd. In de toekomst +zullen er echter meer en meer TSR's verschijnen, met +mogelijkheden waar de MSX gebruiker tot voor kort alleen +maar van kon dromen. + + T S R S L A D E N + +TSR programma's zijn te herkennen aan de extensie van de +bestandsnaam: ze eindigen op .TSR. Deze files bevatten naast +de eigenlijke programmacode ook alle informatie die nodig is +om de TSR goed in het geheugen te installeren. + +Om bijvoorbeeld de demonstratie TSR 'CAPS' - die overigens +niets anders doet dan het Caps lampje laten knipperen - te +laden moet onder MSX-DOS ingetikt worden: + +TL CAPS + +Er mogen meerdere TSR-bestandsspecificaties achter elkaar +worden opgegeven. Indien MSX-DOS2 gebruikt wordt, mag ook de +subdirectory worden opgegeven, waaruit de TSR geladen moet +worden. Bijvoorbeeld, door middel van het volgende commando +worden zowel de TSR `CAPS' ingeladen, als ook alle TSR's +waarvan de bestandsnaam begint met `DEMO'. + +TL CAPS DEMO* + +`TL' betekent `TSR-Load', het is het programma dat de TSR +laadt en in het geheugen plaatst. Ook onder BASIC is een +versie van TSR-Load beschikbaar, zie hiervoor het hoofdstuk +`MemMan BASIC statements'. + +Zodra TL de TSR in het geheugen geinstalleerd heeft zal het +programma actief worden. In bovenstaand voorbeeld wil dat +zeggen dat het CAPS lampje zal gaan knipperen en bij iedere +toetsaanslag het cassetterelais aan of uit geschakeld wordt. + +TL is een slim programma. Zolang er in het MemMan segment +nog ruimte is voor TSR's zullen ze daar geplaatst worden. +Alleen als dat ook echt nodig is wordt een nieuw segment +gebruikt, dat voor overige toepassingen dan onbereikbaar +gemaakt wordt. Dat gebeurt bijvoorbeeld als er een +uitzonderlijk groot TSR programma wordt geladen. Wanneer er +vervolgens weer een kleinere wordt geladen zal TL eerst alle +bestaande TSR segmenten aflopen om te zien of er ergens nog +ruimte is. De volgorde waarin de TSR's geladen worden zal +dan ook geen invloed hebben op het geheugengebruik. + + + T S R S B E K I J K E N + +Het is ten aller tijde mogelijk te kijken welke TSR's er op +dit moment in het geheugen actief zijn. Daartoe bevat het +MemMan pakket de utility TV, TSR-View. Het gebruik is de +eenvoud zelf: gewoon achter de DOS prompt intikken: + +TV + +Er zal een overzicht verschijnen van de op dit moment +actieve TSR's, compleet met hun volledige naam. Deze naam +moet voor iedere TSR uniek zijn, en zal dan ook vrijwel +altijd de initialen van de programmeur bevatten. Deze naam +is dus een andere dan de bestandsnaam! + +Het is deze volledige naam - het TSR ID - die nodig is als +een TSR uit het geheugen verwijderd moet worden. Ook +programma's die direct met TSR's samenwerken kunnen deze +naam gebruiken om te zien of een TSR in het geheugen +aanwezig is. + + + + T S R S V E R W I J D E R E N + +Zoals gezegd is het ook mogelijk TSR programma's weer uit +het geheugen te verwijderen. Het benodigde programma heet +TK, TSR-Kill. TK zorgt er voor dat een TSR netjes verwijderd +wordt. Alle andere TSR's blijven vlekkeloos doorwerken, als +de TSR als enige in een segment stond wordt dat segment weer +vrijgegeven voor gebruik door overige toepassingen. + +Om bijvoorbeeld het het Caps lampje weer normaal te laten +werken en het knipperen uit te schakelen is het verwijderen +van de betrokken TSR voldoende. Daartoe tikt u: + +TK "MJVcapsblink" + +Hierbij dient de volledige naam van de TSR tussen +aanhalingstekens opgegeven te worden. Er kunnen meerdere +TSR's in ��n keer worden verwijderd, door de namen achter +elkaar in te voeren. Bijvoorbeeld: + +TK "TSR naam 1" "TSR naam 2" "TSR naam 3" + +TSR-Kill kan behalve geheugen weer vrijmaken voor gebruik, +ook gebruikt worden om vastgelopen TSR's uit het geheugen te +verwijderen. Een TSR die om welke reden dan ook niet meer +vlekkeloos functioneert zal met behulp van TK meestal nog +wel verwijderd kunnen worden. Vervolgens kan de TSR met TL +weer geladen worden, op dezelfde manier als het opnieuw +starten van gewone programma's nog wel eens wil helpen geldt +dat ook voor TSR's. + + +M E M M A N B A S I C - S T A T E M E N T S + +Vanaf versie 2.3 bevat MemMan enkele statements en functies +die vanuit MSX-BASIC toegepast kunnen worden. Hiertoe is +MemMan van een systeem TSR voorzien, met de ID-naam "MST +TsrUtils". Deze TSR heeft volgnummer 0 en kan niet door +TSR-Kill verwijderd worden. Hieronder volgt een beschrijving +van de beschikbare BASIC-instructies. De betekenis van de +gebruikte symbolen is als volgt: + +[] Wat tussen vierkante haken staat mag worden weggelaten. +<> Omschrijvingen van parameters staan tussen gehoekte +haken. +()", Ronde haken moeten worden ingetikt, evenals leestekens +en comma's. + + +Commando: TSR-Load +Syntax: CMD TL("",[T],[],[]) +Soort: Statement +Voorbeeld:CMD TL("PB") +CMD TL("ALARM",T,,A) +Functie: Laadt een TSR-bestand in het geheugen. + = Naam van het TSR-bestand. Onder + MSX-DOS2 mag een subdirectory worden + opgegeven. +T = Toon de intro-tekst van de TSR. + = Naam van een string-variabele waarin + de TSR ID-naam zal worden opgeslagen. + = Variabele waarin een foutcode wordt + opgeslagen. Indien deze variabele + wordt weggelaten, zal in geval van + laadfouten een standaard BASIC- + foutmelding worden gegeven. De + foutcodes zijn als volgt: + + 0 = TSR met succes ingeladen + 1 = Installatie door de TSR afgebroken + 2 = Structuurfout in TSR bestand + 3 = TSR-tabel vol + 4 = Hook-tabel vol + 5 = Geen vrij MemMan segment + 6 = Te weinig vrij BASIC werkgeheugen + + +Commando: TSR-Kill +Syntax: CMD TK("") +Soort: Statement +Voorbeeld:CMD TK("MJV printbuf") +Functie: Verwijdert een TSR uit het geheugen. + = Identificatienaam van de te + verwijderen TSR. Deze naam kan + worden opgevraagd door middel van + TSR-View of Find-TSR. + + +Commando: TSR-View +Syntax: CMD TV +Soort: Statement +Functie: Toont een overzicht van de ID-namen van alle +actieve TSR's. + + +Commando: Find-TSR name +Syntax: ATTR$ FT("") +Soort: Functie +Voorbeeld:IF ATTR$ FT("CAPS") THEN CMD TK("CAPS") +Functie: Levert de waarde -1 indien de opgegeven TSR is +ge�nstalleerd, levert anders de waarde 0. + = Identificatienaam van de TSR. + + +Commando: Find-TSR number +Syntax: ATTR$ FT() +Soort: Functie +Voorbeeld:N$ = ATTR$ FT(0) +Functie: Levert de ID-naam van de TSR met het opgegeven +volgnummer. Indien het volgnummer groter is dan +het aantal actieve TSR's, dan wordt een lege +string met lengte 0 teruggeven. \ No newline at end of file diff --git a/sunrise_special/1/memman_2.3_specificaties.md b/sunrise_special/1/memman_2.3_specificaties.md new file mode 100644 index 0000000..9864dc1 --- /dev/null +++ b/sunrise_special/1/memman_2.3_specificaties.md @@ -0,0 +1,641 @@ +# M E M M A N 2 . 3 S P E C I F I C A T I E S + + +File : MM23SPEC.TXT +Datum: 19 september 1991 +Door : Ries Vriend / Ramon van der Winkel - c MST + +Deze tekst bevat de informatie die nodig is voor het +schrijven van MemMan 2.3 toepassingsprogramma's. Voor +specifieke specificaties omtrend het programmeren van TSR's +wordt echter verwezen naar de technische documentie die te +vinden is op de `TSR-Development disk'. Hierop staan de +volledige TSR specificaties en enkele TSR ontwikkel tools. +Deze disk kan besteld worden bij het MST, zie voor meer +informatie hierover de LezersService van MSX Computer +Magazine. + + +Wijzigingen in MemMan 2.3 ten opzichte van versie 2.2: + +- De functie XTsrCall (61) is toegevoegd. Deze functie werkt +identiek aan de functie TsrCall (63), het Tsr-ID wordt +echter verwacht in register IX in plaats van BC. Hierdoor +komt register BC vrij om als invoerparameter gebruikt te +worden. + +- Door middel van de functie Info (50) kan het adres worden +opgevraagd waarop XTsrCall rechtstreeks kan worden +aangeroepen. + +- De funtie status (31) is verbeterd. De totale hoeveelheid +bruikbaar werkgeheugen in de computer wordt nu correct +gemeld, ook onder MSX-DOS2. + +- De Alloc (10) functie herkent nu ook geheugen dat +beschikbaar komt wanneer de DOS2 RAMdisk wordt verwijderd of +verkleind! Het maakt daarbij niet meer uit of de RAMdisk +wordt aangemaakt voor- of nadat MemMan werd ge�nstalleerd. + +- De interne stack van MemMan die gebruikt worden om +functieaanroepen te verwerken is vergroot tot 240 bytes, in +plaats van 160. In de praktijk bleek dat de functiestack van +MemMan 2.2 te krap was om geneste "tsrCalls" te verwerken. + + + G E B R U I K T E T E R M I N O L O G I E + +Segment - Geheugenblok van 16kB. Segmenten komen voor in +Pagina specifieke segmenten (PSEG) en Flexibele segmenten +(FSEG). De Flexibele segmenten kunnen op de pagina's 0,1 en +2 worden aangeschakeld. De Pagina specifieke segmenten +alleen op hun eigen pagina. Er zijn drie soorten pagina +specifieke segment: PSEG0000, PSEG4000 en PSEG8000. Ze zijn +op respectievelijk pagina 0,1 en 2 aanschakelbaar. + +Heap - Blok geheugen in pagina 3 (ergens tussen &HC000 en +&HFFFF) waarvan MemMan toepassingsprogramma's een stuk aan +kunnen vragen en daarna vrij mogen gebruiken. + +FastUse - Zelfde als Use, maar dan het adres waarop de +routine direct aan te roepen is in pagina 3. + +UnCrash - Om te voorkomen dat segmenten aangevraagd zijn en +door een crash van een programma nooit meer vrij zouden +worden gegeven, voert de IniChk routine een unCrash uit. +Hierbij worden alle segmenten weer vrijgegeven. Het +unCrashen van een segment is te voorkomen door een segment +de Reserved status te geven. Dit kan met de functie SetRes +(11). Normaal gesproken hoeft een segment niet de Reserved +status gegeven te worden. + + + D E P R I N C I P E S + +MemMan verdeelt het aanwezige geheugen in segmenten van 16 +kB. Voordat een segment gebruikt mag worden moet het worden +aangevraagd. Na gebruik dient het weer te worden +vrijgegeven. Er zijn twee soorten segmenten: de zogenaamde +pagina-specifieke ofwel PSEG's en de flexibele FSEG's. + +PSEG's zijn segmenten die aangevraagd worden voor het +gebruik op een bepaalde pagina, bijvoorbeeld van +&h4000-&h7FFF of van &h8000-&hBFFF. Wanneer er een PSEG +aangevraagd wordt zal MemMan zo mogelijk geheugensegmenten +toewijzen die niet in een memory-mapper zitten. + +FSEG's zijn segmenten die op elke willekeurige pagina kunnen +worden ingeschakeld. Deze segmenten komen altijd uit memory +mappers. Welk soort segment er ook aangevraagd wordt, MemMan +zal een 16-bits 'segmentcode' teruggeven. Deze segmentcode +is weer nodig bij het inschakelen of het weer vrijgeven van +het segment. Wie alleen maar geheugen nodig heeft in het +gebied van &h8000 tot &hBFFF kan dus het beste PSEG's +aanvragen. MemMan gebruikt dan eerst zoveel mogelijk +geheugen uit de 'oude' 16- en 64 Kb modules en gaat dan de +mapper gebruiken. + +Met behulp van MemMan hoeft er dus nooit meer naar geheugen +gezocht te worden. Simpelweg een pagina aanvragen, gebruiken +en uiteindelijk weer vrijgeven. Zo eenvoudig is dat. + +Overigens is er een pagina die zich met MemMan niet laat +schakelen. Pagina 3 bevat behalve de MemMan code zelf ook de +stack (meestal) en een grote hoeveelheid systeemvariabelen. +Er zitten nogal wat haken en ogen aan het wegschakelen van +dat alles. + + + F U N C T I E O M S C H R I J V I N G + +MemMan functies kunnen worden uitgevoerd door een aanroep +van de `Extended BIOS' of EXTBIO hook, op adres &HFFCA. Het +device ID van MemMan - 'M' oftewel &H4D - moet in register D +worden geplaatst. Register E dient het MemMan functienummer +te bevatten. Na aanroep van een MemMan functie kunnen alle +registers gewijzigd zijn, behalve indien het tegendeel wordt +vermeld bij de functie-omschrijving. + +Omdat de EXTBIO hook gebruikt wordt voor diverse systeem +uitbreidingen zoals Kanji en RS232 interfaces, is het +mogelijk dat MemMan functie-aanroepen bijzonder langzaam +verwerkt worden. De prestaties van de MemMan +toepassingsprogramma's kunnen aanmerkelijk worden verhoogd +door functie afhandelingsroutine van MemMan rechtstreeks aan +te roepen, in plaats van de EXTBIO hook. Het adres waarop de +functie afhandelingsroutine aangeroepen kan worden, kan +worden opgevraagd via de info functie (50). + +De meeste MemMan functies bevinden zich in een apart +geheugensegment in pagina 1. Deze functies schakelen over op +een een interne stack, waardoor MemMan +toepassingsprogramma's met een betrekkelijk kleine stack +kunnen volstaan. Door een MemMan functie worden maximaal +twintig bytes op de stack van het toepassingsprogramma +geplaatst. Dit geldt echter alleen indien de functie +rechtstreeks, of via de MemMan functie-afhandelingsroutine +wordt aangeroepen. + +Een functie-aanroep via de EXTBIO hook kan echter een +bijzonder grote stack vereisen. Dit wordt veroorzaakt +doordat alle uitbreidings-modules die aan de EXTBIO hook +gekoppeld zijn elkaar aanroepen, net zo lang totdat ��n +module de functieaanroep herkent. Wanneer er tussendoor ook +nog interrupts afgehandeld worden, kan het stackgebruik +sterk oplopen. Al met al kan gesteld worden dat er bij een +aanroep van de EXTBIO hook minimaal 150 bytes stackruimte +beschikbaar moet zijn. + +Het is derhalve verstandig om via de info functie (50) het +adres op te vragen van de routine die de MemMan functie +aanroepen afhandelt. Wanneer deze routine vervolgens +rechtstreeks aangeroepen wordt, wordt de verwerkingssnelheid +verhoogd en blijft het stack-gebruik beperkt. + +De interruptstand blijft na een MemMan functie-aanroep in +meeste gevallen ongewijzigd. Sommige functies zoals de +diverse (Fast)Use functies schakelen de interrupts echter +uit. Wanneer een MemMan functie werd aangeroepen met de +interrupts uit, zal MemMan nooit terugkeren met de +interrupts ingeschakeld. + +Deze eigenschap is bijvoorbeeld van belang voor TSR +programma's die slechts een zeer kleine stack ter +beschikking hebben. Zo lang de interrupts uit staan, kunnen +alle MemMan functies zonder problemen worden uitgevoerd, +mits de functie verwerkingsroutine van MemMan rechtstreeks +wordt aangeroepen. Wanneer de interrupts echter aan staan is +een grote stack vereist, omdat de +interrupt-verwerkingsroutine enkele tientallen bytes op de +stack plaatst. + + +Naam : Use0 +Nummer : 0 +Functie: Aanschakelen van een segment op pagina 0 + (adresgebied 0000..3FFF) +In : HL = Segmentcode +Uit : A = Resultaatcode (-1 = Mislukt, 0 = Gelukt) + +Het inschakelen van een segment in pagina 0 is alleen +mogelijk indien het segment de MSX-standaard slot-schakel +entry points bevat. + +Opm: Deze functie mag niet worden aangeroepen via de EXTBIO +hook. Deze functie mag alleen worden uitgevoerd door een +rechtstreekse aanroep van de MemMan functie +afhandelingsroutine of de FastUse0 functie. De adressen +waarop deze routines aangeroepen kunnen worden, kunnen via +de info functie (50) worden verkregen. + + +Naam : Use1 +Nummer : 1 +Functie: Aanschakelen van een segment op pagina 1 + (adresgebied 4000..7FFF) +In : HL = Segmentcode +Uit : A = Resultaatcode (-1 = Mislukt, 0 = Gelukt) + +Opm: Deze functie mag niet worden aangeroepen via de EXTBIO +hook. Deze functie mag alleen worden uitgevoerd door een +rechtstreekse aanroep van de MemMan functie +afhandelingsroutine of de FastUse1 functie. De adressen +waarop deze routines aangeroepen kunnen worden, kunnen via +de info functie (50) worden verkregen. + + +Naam : Use2 +Nummer : 2 +Functie: Aanschakelen van een segment op pagina 2 + (adresgebied 8000..BFFF) +In : HL = Segmentcode +Uit : A = Resultaatcode (-1 = Mislukt, 0 = Gelukt) + +Opm: Deze functie mag niet worden aangeroepen via de EXTBIO +hook. Deze functie mag alleen worden uitgevoerd door een +rechtstreekse aanroep van de MemMan functie +afhandelingsroutine of de FastUse2 functie. De adressen +waarop deze routines aangeroepen kunnen worden, kunnen via +de info functie (50) worden verkregen. + + +Naam : Alloc +Nummer : 10 +Functie: Aanvragen van een segment +In : B = Segment voorkeuze code +Uit : HL = Segmentcode. (0000 = Geen segment meer vrij) + B = Segmentsoort code (-1 = FSeg, 0 = PSeg) + +Segment voorkeuze code overzicht (Register B): + +Bit 7 6 5 4 3 2 1 0 +^ ^ ^ ^ ^ ^ ^ ^ +| | | | | | | | +| | | | | | +-+--> Segment Type. 00 = PSEG0000 +| | 0 0 0 0 01 = PSEG4000 +| | 10 = PSEG8000 +| | 11 = FSEG +| +--------------> 1 = Prefereer TPA oftewel het +| standaard MSXDOS RAM slot ++----------------> 1 = Prefereer onge�xpandeerd (dus + snel) slot + +De bits 5 tot en met 2 zijn niet gebruikt en moeten 0 zijn. + +Mocht een PSEG type aangevraagd, maar niet beschikbaar zijn +wordt - indien mogelijk - een FSEG ter beschikking gesteld +die dan het PSEG kan vervangen. + + +Naam : SetRes +Nummer : 11 +Functie: Segment de Reserved status geven +In : HL = Segmentcode + +Geeft een segment de `Reserved-status'; zodat het segment +niet automatisch wordt vrij gegeven na aanroep van de IniChk +routine. Normaal gesproken hoeven programma's de reserved +status niet te zetten, behalve als een programma - +bijvoorbeeld een Ramdisk - een segment voor eigen gebruik +zeker wil stellen. + + +Naam : DeAlloc +Nummer : 20 +Functie: Teruggeven van een segment +In : HL = Segmentcode + +Bij het verlaten van een programma dient deze functie +gebruikt te worden om alle aangevraagde segmenten weer terug +te geven aan MemMan. De eventuele reserved status van het +terug te geven segment wordt door DeAlloc automatisch +opgeheven. + +Segmenten die ook door DOS2 beheerd worden, worden door de +DeAlloc functie weer ter beschikking gesteld van DOS2. + + +Naam : ClrRes +Nummer : 21 +Functie: Reserved status van het segment opheffen +In : HL = Segmentcode + +Het is niet nodig deze functie vlak voor DeAlloc aan te +roepen. DeAlloc heft zelf de Reserved status van het segment +op. + + +Naam : IniChk +Nummer : 30 +Functie: Initialisatie MemMan voor een programma +In : A = Controle code +Uit : A = Controle code + "M" + DE = Versie nummer (format: Versie #D.E) + +Deze routine telt de ascii-waarde van de letter "M" op bij +de inhoud van register A. Hierdoor kan er een MemMan +aanwezigheids controle uitgevoerd worden. Verder wordt er +een unCrash uitgevoerd en worden de segmentcodes van de +actief aangeschakelde sloten berekend en opgeslagen voor +CurSeg. + +De IniChk functie mag slechts ��n keer door ieder MemMan +toepassings programma aangeroepen worden. Dit aanroepen van +IniChk dient te gebeuren voordat de overige functies van +MemMan aangroepen worden. TSR programma's mogen de IniChk +functie nooit aanroepen. + + +Naam : Status +Nummer : 31 +Functie: Status gegevens van MemMan ophalen +Uit : HL = Aantal aanwezige segmenten + BC = Aantal nog vrije segmenten + DE = Aantal segmenten in dubbel beheer bij DOS2 en + MemMan + A = Connected Status van de aangesloten hardware. + Bit Functie + 0 1=Dos2 Mapper Support Routines aanwezig + 1-7 Gereserveerd, altijd 0 + +Als bit 0 van de Connected status gezet is, zijn de +geheugenbeheer functies van DOS 2.20 aanwezig. + +Het aantal nog vrije segmenten kan lager zijn dan is +aangegeven in register BC, omdat sommige segmenten na de +installatie van MemMan door DOS2 gebruikt zijn - om +bijvoorbeeld een ramdisk te installeren. + +Naam : CurSeg +Nummer : 32 +Functie: Segmentcode van een aangeschakeld segment opvragen. +In : B = Paginanummer (0,1,2,3) +Uit : HL = Segmentcode +A = Segmentsoort code (255 = FSeg, 0 = Pseg) + +Deze routine geeft de huidige segmentcode terug van een van +de vier pagina's. + +TSR programma's mogen deze functie niet gebruiken om het +actieve segment in geheugen pagina 0 te bepalen. Om tijd te +sparen wordt deze stand niet automatisch bepaald en +opgeslagen bij de aanroep van een TSR. De actieve segmenten +in de pagina's 1 en 2 worden echter bij iedere hook-aanroep +opnieuw bepaald en kunnen ten alle tijde via deze functie +opgevraagd worden. Omdat in pagina 3 altijd hetzelfde +segment actief is, is ook de segmentcode van pagina 3 altijd +opvraagbaar. + +Een snellere variant van deze functie is FastCurSeg routine. +gebruikt. Het adres waarop deze routine aangeroepen kan +worden is via de Info functie (50) op te vragen. + + +Naam : StoSeg +Nummer : 40 +Functie: Huidige segmenten stand opslaan +In : HL = Buffer adres (9 bytes groot) + +De voor MemMan bekende segmentcodes van de actief +aangeschakelde sloten worden opgeslagen in het buffer. Deze +segmentcodes zijn in beginsel door IniChk berekend en later +door de Use functies geupdate. De opgeslagen stand is niet +de huidige stand, maar de voor MemMan bekende stand. TSR +kunnen hiermee dus niet de actieve stand opslaan. + +Opm: Deze functie mag niet worden aangeroepen via de EXTBIO +hook. Deze functie mag alleen worden uitgevoerd door een +rechtstreekse aanroep van de MemMan functie +afhandelingsroutine. Het adres waarop deze routine +aangeroepen kan worden, kan via de info functie (50) worden +verkregen. + +Natuurlijk kunnen ook de (Fast)CurSeg functies gebruikt +worden om de momentele segment-stand op te vragen. + + +Naam : RstSeg +Nummer : 41 +Functie: Opgeslagen segment-stand actief maken +In : HL = Buffer adres + +De in het buffer opgeslagen segment-stand wordt weer actief +gemaakt en wordt opgeslagen voor CurSeg. + +Opm: Deze functie mag niet worden aangeroepen via de EXTBIO +hook. Deze functie mag alleen worden uitgevoerd door een +rechtstreekse aanroep van de MemMan functie +afhandelingsroutine. Het adres waarop deze routine +aangeroepen kan worden, kan via de info functie (50) worden +verkregen. + +Natuurlijk kunnen ook de (Fast)Use functies gebruikt worden +om een segment-stand te herstellen. + + +Naam : Info +Nummer : 50 +Functie: Geeft informatie over onder andere aanroep-adressen +van MemMan functies +In : B = Informatie nummer (0..8) +Uit : HL = Informatie + +Informatie nummer overzicht. Tussen haakjes staan de +equivalente MemMan functie codes: + +0 - Aanroepadres van FastUse0 (functie 0) +1 - Aanroepadres van FastUse1 (functie 1) +2 - Aanroepadres van FastUse2 (functie 2) +3 - Aanroepadres van TsrCall (functie 63) +4 - Aanroepadres van BasicCall +5 - Aanroepadres van FastCurSeg (functie 32) +6 - Aanroepadres van MemMan, de functie-afhandelingsroutine +7 - Versienummer van MemMan, format: Versie #H.L +8 - Aanroepadres van XTsrCall (functie 61) + +De bovengenoemde functie-adressen mogen door een +toepassingsprogramma of TSR rechtstreeks aangeroepen worden. +Alle entry adressen liggen gegarandeerd in pagina 3. + +De functies worden snel uitgevoerd omdat de MemMan CALL naar +de EXTBIO hook vervalt en de functie-codes in registers D en +E niet uitgeplozen hoeven worden. Een ander voordeel is dat +parameters ook via het register DE doorgegeven kunnen +worden, dit is vooral van belang bij de TsrCall en BasicCall +functies. + +Bijvoorbeeld, de initialisatie routine van een TSR kan de +benodigde functieadressen via de INFO functie opvragen en +deze vervolgens voor later gebruik in de TSR programmacode +opslaan, wat de snelheid van het TSR programma zeer ten +goede kan komen. + +Een exacte beschrijving van de bovenstaande functies kan +gevonden worden bij de MemMan functie waarvan het nummer +tussen haakjes is aangegeven. + +Houd echter onder de aandacht dat de `snelle' functies op de +volgende punten van de gewone MemMan functies verschillen: + +fastUse0-2: Schakelt een segment in in een bepaalde geheugen +pagina. Zie de omschrijving bij de memMan `Use' functies. + +tsrCall: Register [DE] wordt ongewijzigd aan de TSR +doorgegeven. Dit in tegenstelling tot functie 63 (TsrCall), +register DE is dan al bezet om het MemMan functienummer in +op te slaan. + +xTsrCall: Alle mainregisters (AF,HL,BC,DE) worden +ongewijzigd aan de TSR doorgegeven. De TSR-ID code dient in +register IX te worden geplaatst. + +basicCall : Heeft geen MemMan functie nummer. + Functie: Aanroepen van een routine in de BASIC + ROM. + In: IX = Call address in pagina 0 of 1 + AF,HL,BC,DE = dataregisters voor de + BASIC-ROM + Uit: AF,HL,BC,E = dataregisters van de + BASIC-ROM + Interrupts disabled + +Via deze functie kunnen TSR's een routine aanroepen die zich +in pagina 0 en/of pagina 1 van het BASIC-ROM bevindt. De +bios moet al in pagina 0 aangeschakeld zijn. In pagina 1 +wordt de BASIC ROM door MemMan aangeschakeld. + +Dit is bijvoorbeeld noodzakelijk om de math-pack routines +aan te kunnen roepen die in pagina 0 van de BASIC ROM +zitten, maar tussendoor ook een aantal routines in pagina 1 +aanroepen. + +De H.STKE (stack error) hook wordt afgebogen, zodat na een +eventueel op getreden BASIC error de interne stacks van +MemMan gereset kunnen worden. + +fastCurSeg: In register [A] komt geen zinnige waarde terug. +De MemMan CurSeg functie (32) geeft aan of het een FSEG/PSEG +betreft. + +memMan: Heeft geen MemMan functienummer + Functie: Rechtstreeks aanroepen van een MemMan + functie. + In: E=MemMan functienummer + AF,HL,BC = Dataregisters afhankelijk + van de aan te roepen functie. + Uit: AF,HL,BC,DE = dataregisters afhankelijk + van de aangeroepen functie. + +Een aanroep van deze routine heeft hetzelfde effect als het +aanroepen van een MemMan functie via de EXTBIO hook. Doordat +echter de aanroep naar de EXTBIO hook vervalt, worden de +overige uitbreidingen die aan deze hook gekoppeld zijn niet +aangeroepen. Hierdoor blijft het stack gebruik beperkt en +wordt de verwerkingssnelheid verhoogd. + + +Naam : XTsrCall +Nummer : 61 +Functie: Roep het driver-entry van een TSR aan +In : IX = ID code van de aan te roepen TSR +AF,HL,DE,BC worden ongewijzigd doorgeven aan de TSR. +Uit : AF,HL,BC,DE komen ongewijzigd terug van de TSR. + +Deze functie is een verbeterde versie van de functie TsrCall +(63). Omdat met deze functie alle main-registers aan de TSR +kunnen worden doorgegeven, verdient het aanbeveling om deze +functie te gebruiken in plaats van functie 63. + +Opm: Deze functie mag niet worden aangeroepen via de EXTBIO +hook, omdat bij een aanroep via EXTBIO het IX-register +verminkt wordt. Roep deze functie daarom rechtstreeks aan, +of gebruik de MemMan functie-afhandelingsroutine. De +adressen waarop deze routines aangeroepen kunnen worden, +kunnen via de info functie (50) worden opgevraagd. + + +Naam : GetTsrID +Nummer : 62 +Functie: Bepaal TSR ID code +In : HL = Pointer naar de TsrNaam (12 tekens). + Ongebruikte posities opvullen met spaties. +Uit : Gevonden: Carry clear (NC) + BC = TSR ID code +Anders : Carry set (C) + + +Naam : TsrCall +Nummer : 63 +Functie: Roep het driver-entry van een TSR aan +In : BC = ID code van de aan te roepen TSR +AF,HL,DE worden ongewijzigd doorgeven aan de TSR. +Uit : AF,HL,BC,DE komen ongewijzigd terug van de TSR. + +Merk op dat alhoewel het DE register ongewijzigd aan de TSR +wordt doorgegeven, het niet voor parameter-invoer benut kan +worden. De Extended BIOS functiecode van MemMan (D='M' E=63) +moet namelijk in dat register geplaatst worden. + +Bij de Fast-TsrCall routine treedt deze complicatie niet op; +het adres van deze routine kan middels de info functie +opgevraagd worden. + + +Naam : HeapAlloc +Nummer : 70 +Functie: Alloceer ruimte in de heap +In : HL = Gewenste grootte van de ruimte (in bytes) +Uit : Genoeg ruimte: HL = Startadres van de ruimte +Anders : HL = 0000 + +Door middel van deze functie kan een stuk geheugen +gealloceerd worden. Het geheugenblok zal zich gegarandeerd +in pagina 3 bevinden. + +De heap is vooral nuttig voor TSR programma's, die hem +bijvoorbeeld als tijdelijke of permanente diskbuffer kunnen +gebruiken. Ook andere buffers - waarvan het absoluut +noodzakelijk is dat ze zich in pagina 3 bevinden - kunnen op +de heap worden geplaatst. + +Aangevraagde blokken geheugen uit de heap blijven +onbruikbaar voor andere programma's totdat een `HeapDeAlloc' +is uitgevoerd (functie 71). + +De grootte van de heap kan worden ingesteld door middel van +het configuratie programma CFGMMAN. + + +Naam : HeapDeAlloc +Nummer : 71 +Functie: Geef geAlloceerde ruimte van de heap weer vrij +In : HL = Startadres van de ruimte + + +Naam : HeapMax +Nummer : 72 +Functie: Geef de lengte van het grootste vrije blok geheugen +in de heap terug +Uit : HL = Lengte van het grootste vrije blok + + +D E S T A C K O N D E R M E M M A N + +MemMan toepassingsprogramma's dienen de stack pointer (SP) +bij voorkeur in pagina 2 of 3 (tussen &h8000 en &HFFFF) te +plaatsen. Indien MemMan door een hook-aanroep geactiveerd +wordt, wordt het huidige segment in pagina 1 (&h4000 tot +&h8000) namelijk weggeschakeld om plaats te maken voor de +TSR-Manager en de eventuele TSR's. Indien de stack zich op +dat moment in pagina 1 bevindt zal de computer vastlopen. + +Indien TSR's na een BDOS call of interrupt via een BIOS-hook +worden aangeroepen treden geen stackproblemen op; ook niet +indien de stack van het toepassingsprogramma in pagina 1 +staat. De BDOS en interruptfuncties gebruiken namelijk hun +eigen stack in pagina 3. De stack bevindt zich dan alsnog in +pagina 3 op het moment dat de hook aangeroepen wordt. + +Bestaande CP/M en MSX-DOS programmatuur is dus zonder +problemen in combinatie met MemMan 2 te gebruiken - maar +alleen indien de standaard BDOS calls gebruikt worden. +Wanneer echter via een interslot call een BIOS routine +rechtstreeks aangeroepen wordt, dient de stack in pagina 2 +of 3 te staan. Reserveer in dat geval minimaal 150 bytes +voor de stack. + + +Appendix 1: BIOS aanroepen onder Turbo Pascal + +Indien in een Turbo Pascal programma interslot-calls naar de +BIOS gebruikt worden, is het belangrijk dat de stack in +pagina 2 of 3 staat. Op het moment dat de BIOS dan een hook +aanroept kan MemMan veilig de TSR's aktiveren. De positie +van de stack is afhankelijk van het maximum programma adres +dat tijdens de compilatie in Turbo Pascal is ingesteld. De +stack bevindt zich in Turbo Pascal direkt onder het +variabelen geheugen. Het variabelen geheugen dient bij +programma's die de BIOS aanroepen dus ruim boven adres +&h8000 geplaatst te worden. + +Is geen source voorhanden, dan is het mogelijk om met een +debugger het stack adres van Turbo Pascal programma's aan te +passen. De initialisatie code van een TP programma ziet er +als volgt uit: + +start: jp init +... +... +init: ld sp,100h +ld hl,nn +ld de,nn +ld bc,nn +call yy +ld hl,nn +ld de,stack ;DE bevat het stack adres, hoeft +ld bc,nn ; alleen aangepast te worden als het +call zz ; lager is dan &h80A0 +... + +Het stackadres in register DE kan bijvoorbeeld op &hC100 +gezet worden. diff --git a/sunrise_special/1/msx_assemblers.md b/sunrise_special/1/msx_assemblers.md new file mode 100644 index 0000000..7da6904 --- /dev/null +++ b/sunrise_special/1/msx_assemblers.md @@ -0,0 +1,274 @@ +# A S S E M B L E R S O P M S X + + +Het schrijven van machinetaalprogramma's op MSX is nooit +echt moeilijk geweest en is daarom ook een prima computer om +het op te leren. Er is in het verleden al veel geklaagd over +het feit dat men wel een modernere processor had kunnen +kiezen om in de MSX te stoppen, maar daarbij werd dan vaak +over het hoofd gezien dat de Z80 een makkelijk te begrijpen +microprocessor is (waarschijnlijk omdat hij een volledig +achterhaalde architektuur heeft). + +Dit verhaal is er op gericht om u kennis te laten maken met +de twee meest gebruikte assemblers op MSX. Deze assemblers +zijn WBASS-2 en GEN80. + + +## G E N 8 0 + +Dit is een redelijk oude assembler die nog uit het CP/M +tijdperk stamt. Het is echter in technisch opzicht een prima +assembler omdat hij redelijk flexibel is en omdat hij met +hele grote listings om kan gaan. + +De hele assembler zit in 1 .COM file en maakt gebruik van de +DOS commando regel om invoer en uitvoer te regelen. +Bij de aanroep kunnen verschillende dingen gespecifiseerd +worden zoals de maximale breedte van een label en dingen met +betrekking tot de uitvoer. + +Voordelen van GEN 80: +- Het is mogelijk om met GEN 80 gebruik te maken van include +files en van macro files. Vooral deze laatste optie is +makkelijk omdat je zo je eigen persoonlijke BIOS bij kunt +houden met routines die je vaak nodig hebt. +- De maximale filelengte van een te assembleren files hangt +feitelijk alleen van de hoeveelheid RAM van je computer af +en van het feit dat er 'maar' 720 kB op 1 disk past. + +Nadelen: +- Omdat de assembler steeds geladen moet worden is het +feitelijk ondoenlijk alleen van disk te werken omdat je +dan gewoon niets opschiet. Het gebruik van een RAM-disk is +eigenlijk onontbeerlijk omdat je anders het grootste deel +van de tijd staat te wachten. +- Omdat GEN 80 onder DOS loopt is het niet echt handig als +je iets wilt testen. Meestal moet je dan eerst naar BASIC +voordat je de creatie kunt testen. Je berijpt dat debuggen +zo een vervelende bezigheid wordt omdat je konstant tussen +DOS en BASIC zit te klooien. +- Het eigen gebruik van de memory mapper is ook niet aan te +bevelen als je op hetzelfde moment alles in een RAM-disk +hebt staan. De kans is dan groot dat je dingen in de +RAM-disk gaat overschrijven waardoor je alles weer opnieuw +moet installeren. + +GEN 80 is een prachtige assembler maar is helaas niet +speciaal voor MSX geschreven. Vooral bij het gebruik van de +memory mapper stoot je hier dus op problemen. Voor het +schrijven van demo's of andere soorten programma's die in +een grafische mode werken is het gebruik van GEN 80 af te +raden om de doodsimpele reden dat hij daar niet voor +geschreven is. + + +## W B A S S - 2 + +Dit is bij mijn weten de enige assembler die speciaal voor +MSX geschreven is. Ik moet hierbij meteen opmerken dat +WBASS-2 niet een assembler is, maar dat het een assembler +bevat. Verder behoren een monitor, een editor en een +disassembler tot de standaard uitrusting. Het gekke is dat +de voordelen en nadelen van GEN 80 precies omgekeerd van +toepassing zijn voor WBASS-2. Zo is het bij WBASS-2 oppassen +dat je niet over je source code heen assembleert, maar daar +staat tegen over dat het gebruik van de memorymapper een +fluitje van een cent is. + +Voordelen van WBASS-2: +- Het is een ge�ntegreerd pakket van ontwikkelsoftware dat +goed met elkaar samenwerkt en waarmee weinig tijd verloren +gaat aan het omschakelen tussen editten en bv. het testen +van een programma. +- Het is mogelijk om tegelijk een assembly programma en een +BASIC programma te gebruiken en te bewerken. +- De assembler is snel (op een turbo R zelfs hemels). +- De assembler is heel flexibel. Zo is het mogelijk om met +verschillende notaties voor getalrepresentatie te werken. +(Zie verder). +- Het pakket biedt een volledige ondersteuning van het +memory-map systeem van de MSX. +- De editor is speciaal geschreven voor de invoer van +assembly (alhoewel er dan altijd nog mensen zijn die +klagen over deze lovenswaardige eigenschap). +- Het pakket biedt een goede ondersteuning van de MSX +file-formaten. Zowel .BIN als .DAT files zijn probleemloos +te laden. +- De editor kan ASCII files genereren, maar het opslaan van +files kan beter in het WBASS-2 formaat gebeuren omdat deze +vorm korter en sneller is. +- Het is met een simpele aanpassing van het laadprogramma +mogelijk om de plaats van het WBASS-2 programma in het RAM +zelf te bepalen (Zet hem dus altijd in de hoogste vrije +RAM page die je hebt). + +Nadelen: + +- De lengte van de te bewerken file is beperkt tot ong. 23kB +- Je moet oppassen dat je niet over je eigen source code +heen schrijft. (Zie voor meer details bij Tips.) +- De Z80 mnemonics liggen redelijk goed vast, behalve die +van de instruktie EX AF,AF' Volgens offici�le Zilog +informatie is deze notatie de enige goeie, maar een aantal +andere Z80 fabrikanten vond dat zeker niet belangerijk en +hebben er EX AF,AF van gemaakt. Om verwarring te voorkomen +kunnen de meeste assemblers beide notaties wel aan, maar +WBASS-2 kan dit niet en zal bij gebruik van de eerste +variant een foutmelding geven. +- WBASS-2 heeft nog een paar kleine bugs die op het eerste +gezicht niet opvallen (zie Tips). +- WBASS-2 kent geen macro's en het include file mechanisme +is niet echt denderend. + +WBASS-2 bevat enkele bugs ! Zo is het gelijktijdig werken +met zowel enkel- als dubbelzijdige disks af te raden omdat +het programma hierdoor in de war kan raken met alle gevolgen +vandien. Dit is bij mijn weten de grootste bug van WBASS-2. +Er zijn geloof ik nog enkele, maar die zijn mij nog niet +opgevallen. + +De nadelen van WBASS-2 zijn met enige oefening en handigheid +op te heffen. Het is gewoon een kwestie van hoe je met het +programma om gaat. Voor MSX is WBASS-2 zonder enige twijfel +het beste pakket omdat het speciaal voor MSX geschreven is. +Hierbij zijn de twee belangerijkste kriteria de snelheid +waarmee tussen testen en assembleren geschakeld kan worden +en de sublieme manier van geheugen management dat het pakket +de gebruiker biedt. + + + Tips voor het gebruik van WBASS-2 + +Tips voor het instellen van het programma: +- In het laadprogramma wordt op een gegeven moment een +OUT &HFD instruktie gegeven vlak voordat de WBASS-2 file +geladen wordt. Deze OUT bepaald op welke RAM page het +programma geladen wordt. Indien je bv. 256 kB hebt zou je +dus het best OUT &HFD,15 kunnen geven omdat het programma +dan niet in de weg zit tijdens het ontwikkelen van je +software. +- De edit data van je eigen programma komt altijd op mapper +page 1 te staan (net als een BASIC programma) en om nu te +voorkomen dat je per ongelijk een programma over je eigen +edit data assembleert kan je het beste een andere page +selekteren (met het PAGE commando) zodat de assembler de +code niet over je source data heen kan schrijven. +Dit werkt echter alleen voor page 2 (&H8000 / &HC000) +omdat je page 3 eigenlijk moet laten staan. Je edit data +kan nl. makkelijk over adres &HC000 heen staan, maar daar +kan je code ook staan. Pas dus altijd op met wat je doet. +(Persoonlijk vind ik dit het allergrootste nadeel van +WBASS-2.) Het is gelukkig mogelijk om op disk te +assembleren inplaats van in RAM zodat je dit probleem op +kunt heffen. +- Het is in het laadprogramma ook mogelijk om het eerste +adres te kiezen voor editdata. Dit gebeurt met de +instruktie: BE=&H9200 Indien je dit adres op &H8000 zet +moet je wel oppassen dat je absoluut niet meer een BASIC +programma gaat invoeren omdat je dan meteen over je source +code heen schrijft. Je kunt deze waarde het beste op +&H8100 zetten zodat je naast je edit data ook nog een +klein BASIC programma in het RAM kunt hebben. +- De include optie van WBASS-2 is zoals vermeld niet echt +denderend. Het houdt feitelijk in dat je in een listing +kunt vermelden dat hij nog een file moet laden die ook +geassembleerd moet worden. Dit kan bij WBASS-2 alleen als +je de include opdracht onderaan de file neer zet omdat de +oude file uit de editbuffer gewist zal worden. Het is +daarom ook niet handig om deze optie te gebruiken omdat +het alleen maar ellende veroorzaakt. + +Voor verdere tips moet ik naar de uitstekende handleiding +verwijzen. + + +## G E T A L R E P R E S E N T A T I E + +Voor Z80 mnemonics bestaan 4 verschillende manieren van +getalsrepresentatie en wel: +- de binaire ( 2 tallig stelsel) +- de oktale ( 8 tallig stelsel) +- de decimale (10 tallig stelsel) +- de hexadecimale (16 tallig stelsel) + +Het is met een zgn. 'prefix' of 'postfix' mogelijk om aan de +compiler te vertellen welk talstelsel bedoeld wordt. In +BASIC zijn dit: +- &Bxxxxxxxx voor een binair getal +- &Oxxx voor een oktaal getal +- xx voor een decimaal getal +- &Hxx voor een hexadecimaal getal + +De meeste Z80 assemblers kunnen deze getalsrepresentatie ook +gebruiken. Er is echter een oudere notatievorm (die ik +persoonlijk wat eleganter vind) en die is als volgt: + +- xxxxxxxxB voor een binair getal +- xxxO voor een oktaal getal +- xx voor een decimaal getal +- xxH voor een hexadecimaal getal + +Hierbij moet opgemerkt worden dat bv. &H7FFF in de tweede +notatie als 07FFFH geschreven moet worden. Die extra 0 is +eigenlijk flauwekul omdat zo'n groot getal niet in een 16 +bits register past. (Nvdr. Die 0 is bij de meeste assemblers +alleen verplicht als het getal met een letter begint (dus +bijvoorbeeld 0F000H). Zo kan de assembler zien dat het om +een getal gaat en niet om een label.) + +WBASS-2 heeft als standaardinstelling de eerste notatievorm +maar kan ook de tweede gebruiken (met het SET commando in te +stellen). Dit is een hele handige optie als je bv. GEN80 +files om wilt zetten naar WBASS-2 files en dat gaat als +volgt. + +Geef op de WBASS-2 commandoregel de commando's: +SET/H a,"H" +SET/B a,"B" + +De getallen zullen nu bekeken worden volgens de tweede +notatievorm. Laad nu de om te zetten file die in ASCII +formaat moet staan. + +Doe nu: +SET/H v,"&H" +SET/B v,"&B" + +Als je nu weer EDIT in typt zullen alle getallen omgezet +zijn naar de eerste notatievorm. Nu hoef je alleen nog maar +het ' teken achter alle EX AF,AF' instrukties weg te halen +en de hele file is omgezet. Andersom werkt dit natuurlijk +ook. + + +Uitleg van begrippen die in dit artikel genoemd zijn + +Voor het geval je niet weet wat macro's zijn komt nu even +een korte uitleg. Macro's zijn vormen van labels die je +gewoon in je assembly code kunt zetten waarna de computer +tijdens het assembleren inplaats van dat label een aantal +instrukties neer gaat zetten. Meestal gebeurt dit in de vorm +van een subroutine. Op deze manier voorkom je dat je voor +elk programma de code van eigen BIOS routines hoeft te +kopi�ren, maar inplaats daarvan vermeld je aleen de file +waar je eigen BIOS calls in staan en hoef je alleen nog maar +de macro in je programma neer te zetten inplaats van de hele +routine. + + +## C O N C L U S I E + +Ik heb gemerkt dat mensen die met GEN 80 werken liever niet +omschakelen naar WBASS-2 en andersom. Ik heb in ieder geval +geprobeerd om een objektief oordeel over beide programma's +te geven. Aan GEN 80 is weinig meer te veranderen, maar +WBASS-2 zou nog uitgebreid kunnen worden. Indien de totale +ruimte voor edit data met 100 kB zou groeien en de gebruiker +precies zou kunnen bepalen waar deze data staat, dan zou +dat een zeer waardevolle aanvulling van het pakket zijn. +Vooral bij de wat grotere programma's wordt het lastig om +toch nog in het RAM te assembleren, maar voor de rest is +WBASS-2 de beste keus voor je MSX assembly creativiteit. + +Alex van der Wal diff --git a/sunrise_special/1/muis_uitlezen.md b/sunrise_special/1/muis_uitlezen.md new file mode 100644 index 0000000..1618c36 --- /dev/null +++ b/sunrise_special/1/muis_uitlezen.md @@ -0,0 +1,216 @@ +# M U I Z E N I S S E N + + +Het valt me telkens weer op dat er op MSX maar weinig +gebruik gemaakt wordt van de muis. Dit in tegenstelling tot +andere systemen waar de muis een absolute noodzaak is +geworden. Het is dan ook een heel slim apparaatje dat een +gigantische brug kan slaan tussen de software en de +gebruiker. Het is toch fantastisch dat er zo'n doosje is dat +als je het beweegt een gelijksoortige beweging van een +voorwerp op het scherm teweeg brengt! + + +## D E G E S C H I E D E N I S + +De muis is ��n van de belangerijkste computerontwikkelingen +van de afgelopen 15 jaar. Voorheen moesten alle commando's +domweg ingetikt worden en dat maakte de computer niet echt +toegankelijk voor het grote publiek omdat de besturing van +die dingen alleen maar door een klein elitair groepje mensen +gedaan kon worden. Daar is met de komst van de muis nu een +radikaal einde aan gekomen. De muis is zelfs zo 'makkelijk' +dat een kind dat nog maar amper praten al met een computer +overweg kan omdat de besturing zo eenvoudig is geworden. + +De muis op zich is niet duur, maar de verdere (grafische) +weergave bleek ontzettend duur te zijn. Daar kwam pas +verandering in toen computers goedkoper werden omdat de +produktie omhoog ging. Plotseling werden massaal video +kaarten (en losse VDP's) gemaakt die de muis nu ook voor het +grote publiek toegankelijk maakten. + + +## D E M U I Z E N V A N N U + +Nu, zoveel jaar later kost een muis niet meer dan 150 +gulden. Er zijn muizen in alle soorten en maten en er is +gelukkig een zekere standarisatie van aansluiting. +Natuurlijk had IBM in haar oneindige wijsheid besloten om de +zaken zo aan te pakken dat er een behoorlijke connector voor +nodig is om een muis aan een PC te hangen, maar er waren +gelukkig ook verstandige mensen die de muis gewoon aan de +bekende 'Joystick' poort connector gehangen hebben. + +Bij mijn weten gebruiken MSX, Amiga en Atari deze connector +en ze zijn ook volledig uitwisselbaar (alhoewel de standaard +meegeleverde muizen van de laatste twee matig tot slecht van +kwaliteit zijn). + +## D E W E R K I N G + +Er zijn ruwweg 3 soorten muizen, waarvan er twee weer op +elkaar lijken, nl: +- de elektro mechanische muis +- de opto mechanische muis +- de optische muis + +De eerste vorm is meteen ook de oudste en gebruikt het +overbekende 'balletje tegen asje' systeem. Aan die twee +assen zitten echter twee pot-meters (variabele weerstand) +die 360 graden kunnen draaien. Door nu de weerstand te meten +kon de positie van de muis berekend worden. Deze vorm had +echter als nadeel dat het balletje makkelijk over de as +gleed waardoor de as niet draaide. Dit slippen werd weer +veroorzaakt doordat de pot-meter teveel wrijvingsweerstand +genereerde. Verder sleten de pot-meters snel waardoor de +weerstandsmeting niet meer goed ging. Deze muizen worden +tegenwoordig niet meer gemaakt en wie er ��n heeft moet dat +ding maar in de kast leggen, want het kon wel eens een +museumstuk worden. + +De tweede soort muis is de meest gebruikte muis, en werkt +precies hetzelfde als de eerste vorm met het verschil dat de +pot-meters vervangen zijn door twee 'wieltjes' met gaten. +Affijn, omdat de meeste mensen de rest van de werking wel +weten zal ik er verder geen woorden over vuil maken. Het +voordeel van deze muis boven de eerste is dat hij niet slijt +en dat er heel weinig wrijvingsenergie op de asjes komt. + +Deze eerste twee vormen hebben echter een gezamelijk nadeel; +als ze vuil worden gaan ze haperen (oftewel wrijving). Dit +nadeel is opgelost met de komst van de volgende generatie +muizen, de optische muis. Deze muis heeft geen bewegende +onderdelen en wrijving heeft dus geen invloed op de +prestaties. Het komt er op neer dat er in de muis een +lichtje brandt samen met een element dat licht opvangt. De +muis wordt bewogen over een mat met horizontale en vertikale +lijnen die licht weerkaatsen. Affijn, als het licht +weerkaatst vangt het andere element het op en zo herkent de +muis dat hij beweegt. + +Al deze muizen werken echter wel met het principe dat ze +verplaatsing meten en niet plaats. Ze leveren dus de +afgelegde afstand tussen twee metingen aan de computer af +die deze meting dan in een positie omzet. Dit gebeurd door +de afstand bij de vorige positie op te tellen. + + +## D E M U I S L E E S A K T I E + +Er is in het verleden nogal wat verwarring geweest over de +vraag hoe een MSX2 de muis leest omdat de VDP van een MSX2 +een hardwarematische muisleesroutine bevat, die echter niet +gebruikt wordt. De twee joystickpoorten zitten op alle +MSX'en aan register 14 en 15 van de PSG en de VDP heeft er +geen bal mee te maken. + +Om een komplete leesaktie te doen is nogal wat nodig omdat +de muis maar de beschikking heeft over een 4 bits databus. +Om dus 2 keer een 8 bits offset te lezen (X en Y) moet er +dus 4 keer gelezen worden waarbij de muis eerst verteld moet +worden dat er gelezen gaat worden. Aan de hand van de +routine (GTMOUS) zal ik nu het algoritme verklaren. + +We nemen even aan dat de muis in poort 1 zit. In dat geval +staat in (PORT) de waarde 10111111B en in (PORT+1) de waarde +00010000B + +GTMOUS: +- Lees PSG register 15 +- Wis bit 6, dit geeft aan dat de muis in poort 1 zit +(Zet bit 6 om aan te geven dat de muis in poort 2 zit) +- Zet bit 4, zodat de muis weet dat nu XH klaargezet moet +worden. Bit 5 doet hetzelfde voor poort 2 +Opm: XH/YH = Bit 4-7 van X/Y offset +XL/YL = Bit 0-3 van X/Y offset +- Wacht even op muis (het is een relatief traag ding) +- Lees XH (Verdere details volgen) +- Lees XL +- Lees YH +- Lees YL +Dit lezen is niet eenvoudig omdat de muis niet automatisch +weet wanneer ��n van de waarden gelezen is. Om aan de muis +te vertellen dat je de waarde gelezen hebt, moet bit 4 +(indien de muis in poort 2 zit bit 5) van PSG register 15 +ge�nverteerd worden. Als tijdens de volgende leesaktie +register 15 weer geschreven wordt zal de muis dit +ge�nverteerde bit zien waarop het beestje de volgende te +lezen waarde op zijn 4 bits databus zet. Na een kleine +wachttijd wordt deze waarde dan uit register 14 gelezen. + + +## E E N M U I S B E S T U R I N G S P R O G R A M M A + +Laat ik beginnen met het bedanken van Stefan Boer die het +basisprogramma voor de muisbesturing heeft gemaakt waar ik +op voortgeborduurd heb. + +De routine is vrij universeel en werkt gegarandeerd op alle +MSX'en (vanaf MSX2). Als uitvoer zal een sprite op het +scherm getekend worden die de beweging van de muis volgt. +Wat meteen opvalt is dat het programma nogal groot is +geworden, maar dat komt omdat er maar heel weinig BIOS calls +gebruikt worden. De muisroutine van de MSX2 en turbo R staat +nl. in een subslot en dat maakt de routine relatief traag. +Voor de meeste routines is dit niet zo'n bezwaar, maar als +een routine vaak aangeroepen wordt is het toch wel handig +dat alles zo vlot mogelijk verloopt. + +Verder bevat het programma een schat aan andere nuttige +informatie. Wat dacht je bv. van de vuurknop uitleesroutine +die feitelijk een kopie is van de routine die in de +interruptafhandelingsroutine van FD9FH staat. Deze routine +kijkt naar alle vuurknoppen (0 t/m 5) en doet dit 5 keer zo +snel als de BIOS routine omdat je die in dit geval 5 keer +aan zou moeten roepen. In principe is deze routine overbodig +omdat er in het systeem RAM ook een byte is waar de huidige +vuurknop status in staat, maar ik heb hem er toch bij gezet +omdat er onder MSX programmeurs de trend bestaat om het hele +systeem plat te leggen zodat er geen processortijd verloren +gaat aan -voor hen- overbodige dingen en in dat geval wordt +dit byte niet meer gezet. + +Verder bevat het programma een routine die voor SCREEN 5, +page 0 twee sprites initialiseert en alle andere sprites weg +definieert. Je merkt het al, dit programma bevat meer dan +alleen maar een simpele muisbesturing. + + +## H O E W E R K T H E T ? + +Als het programma opgestart wordt zullen eerst de benodigde +sprites ge�nitialiseerd worden. Daarna zal naar een muis +gezocht worden (CHKPRT) die in de variabele (PORT & PORT+1) +aangeeft of en in welke poort de muis zich bevindt. Is geen +muis aangesloten dan zal de waarde 0 in (PORT) staan. Nu +wordt nog een interruptroutine ge�nstalleerd die bij elke +interrupt de sprites zal herplaatsen. + +Verder zal de routine ook altijd met de cursorkeys werken +(logisch nietwaar??). Het uiteindelijke resultaat is dus +een hele snelle routine die zelf wel uitzoekt of en waar een +muis is aangesloten en die zowel met muis als met de +cursorkeys tegelijkertijd een 'arrow' over het scherm kan +bewegen in een van tevoren opgegeven venster. + +Een ander leuk detail is dat de muisroutine op zich ook op +MSX1 werkt, maar dat dan wel de muisplaats en initialiseer +routines herschreven moeten worden. + +Voor meer informatie over het hoe en wat van sprites moet ik +jullie naar ��n van mijn eerdere artikelen verwijzen die op +de GENIC ClubGuide Special #2 staat. + +Het programma staat los op deze disk (hoop ik) en heet +MOUSE.ASC Als u niet zo'n ster bent in het bedienen van een +assembler kunt u ook gewoon het programma MOUSE.BIN +opstarten. + +Ik hoop dat ik wat duidelijkheid heb gebracht in de wereld +van MSX muizen en natuurlijk wil ik in de toekomst een +stormvloed van programma's zien die de muis gebruiken, dat +spreekt voor zich (ik bedoel dus dat ik hoop dat dit muisje +nog een staartje krijgt). + +Alex van der Wal diff --git a/sunrise_special/1/pointers_in_pascal.md b/sunrise_special/1/pointers_in_pascal.md new file mode 100644 index 0000000..d415749 --- /dev/null +++ b/sunrise_special/1/pointers_in_pascal.md @@ -0,0 +1,178 @@ +#P O I N T E R S + + +Ik wil in dit stukje wat uitleg geven over pointers; wat kun +je er zoal mee doen, hoe ga je er mee om. Ik ga in principe +uit van een de taal Pascal, maar dit verhaal is met wat +fantasie om te zetten naar bijvoorbeeld machinetaal of +BASIC. + + +## W A T I S E E N P O I N T E R + +Een pointer is in feite een adres en op dat adres staat de +inhoud van een variabele. De variabele waar een pointer naar +wijst is meestal alleen via deze pointer toegankelijk. Om +het allemaal moeilijk te maken kun je ook nog pointers naar +pointers (naar pointers naar pointers enz.) hebben. + + +## W A A R O M P O I N T E R S G E B R U I K E N + +Voor het structureren van 'gelijksoortige data-elementen' +(dus bv. integers, arrays, bytes, records) zijn er in Pascal +in principe 3 mogelijkheden: de array, de file en pointers. + +De file is vooral bedoeld als in- en uitgangsmedium en niet +in de eerste plaats voor interne verwerking (daarvoor zijn +de mogelijkheden gewoon te klein). + +Arrays van een bepaald type bieden wel ruime verwerkings- +mogelijkheden, maar er kleven ook een aantal bezwaren aan, +waarvan de belangrijkste is dat we verplicht zijn de array +in een preciese omvang te declareren (bijvoorbeeld +array[1..100] of byte; deze array heeft een vaste omvang van +100 bytes), terwijl de omvang van de omvang van de rij die +in de array moet komen bijna nooit van te voren bekend is. +Hierdoor is bijna altijd de array te groot of te klein. + +Pascal biedt nog een andere structureringsmogelijkheid en +wel door middel van pointers. Hierbij zijn geen van de bij +de file en array genoemde bezwaren van toepassing. Aan +pointers kleven echter weer andere bezwaren, o.a. dat het +netwerk van pointers waarmee je werkt soms enorm complex kan +worden, maar aan de andere kant zijn er ook erg veel +voordelen. + + +## D E S P E L R E G E L S + +* TYPE-DEFINITIE +Een pointer-type wordt in pascal als volgt gedefinieerd: + + = ^ + +Voorbeeld: +type arint = array[1..100] of integer; +rek = record +a : integer; +x, y : byte; +z : array[1..24] of char +end; +PTRint = ^integer; +PTRari = ^arint; +p_rek = ^rek; + + +* POINTER-VARIABELE +We kunnen nu pointer-variabelen declareren aan de hand van +de zojuist gemaakte type-definities. + +Voorbeeld: +var p1, p2, p3 : PTRint; +p4, p5 : p_rek; + +Het bovenstaande creeert de pointers (zoals var ook alle +andere variabelen creeert). Een pointer heeft op een +MSX-computer een 'grootte' van 2 bytes, want daarin past +precies het gehele geheugen- bereik van 64 kB. + +* POINTER-OPERATIES +Er zijn drie manieren om aan een pointer-variabele een +waarde te geven: +- Met de standaard-procedure NEW. +Aanroep: NEW(p), waarbij p de betreffende +pointer-variabele is. + +Door de aanroep van NEW(p) wordt er in het geheugen van +de computer ruimte gereserveerd ter grootte van het +data-type waarnaar de pointer wijst. Als ik dus een +pointer naar een byte heb (^byte) dan wordt er dus ook +werkelijk 1 byte geheugen vrijgemaakt voor dat byte. + +Na de NEW-instructie kun je de pointervariabele een +waarde geven. Dit gaat bijna zoals bij iedere andere +variabele; via de pointer geef je de pointer variabele +nu een waarde. +scrijfwijze: ^ := + +Voorbeeld: +NEW(p1); { maak ruimte voor p1^ } +p1^ := 25; { geef pointervariabele p1^ de waarde 25 } + +- We kunnen een pointer-variabele ook de waarde geven van +een andere pointer-variabele via een assignment: Stel p1 +en p2 zijn pointers naar hetzelfde type pointer- +variabele (dit is erg belangrijk). Met p2 := p1 laat je +deze poinbters naar dezelfde variabele wijzen. p1 en p2 +zijn nu dus verschillende aanduidingen voor dezelfde +variabele... + +Er is een groot verschil tussen: +1) new(p1); 2) new(p1); +p1^ := 25; p1^ := 25; +new(p2); p2 := p1; +p2^ := 25; + +Er geldt na afloop: +1) p1^ = p2^ 2) p1^ = p2^ +twee variabelen een variabele +p1 <> p2 p1 = p2 + +- De derde mogelijkheid is om de pointer de waarde nil te +geven; hij wijst dan nergens naar. + +Voorbeeld: +p1 := nil; + + +Een gecreeerde variabele kunnen we ook weer vernietigen en +wel met de standaard-procedure DISPOSE. + +Voorbeeld: +dispose(p); + +Hierna is de variabele p^ vernietigd; de geheugenruimte +die door deze variabele bezet werd is weer vrijgegeven en +is dus weer beschikbaar. De pointer p is ongedefinieerd. + + +## T E N S L O T T E + +Je kunt met pointers leuke dingen uithalen. Zo kun je +bijvoorbeeld een 'gelinkte lijst' opzetten. Dit is een +array-achtig iets, waarbij je echter geen indexen en geen +vaste omvang hebt (wat je bij een array juist wel hebt). Je +creeert een record waarin een pointer zit die naar 'zijn +eigen' record wijst. + +Hierbij krijg je echter een kip-en-ei-probleem: als ik eerst +de pointer definieer, dan is het record nog niet bekend maar +als ik eerst het record definieer dan heb ik weer geen +pointer om naar dat record te laten wijzen. + +Dit is in pascal de enige toestand waarbij je een pointer +mag definieren naar een nog (!) niet-bestaand type. + +De definitie van de data-typen ziet er bijvoorbeeld zo uit: +type PTRrek : ^rek; { pointer naar type rek } +rek : record +A : array[1..7] of byte; +B : boolean; +next : PTRrek; { pointer naar het volgende + element in de lijst } +end; + +var startpunt, huidig : PTRrek; +^ ^ +| | +| +-- op deze plek in de lijst ben ik nu +| ++------------- eerste element uit de lijst (de 'wortel') + + +Bij lijsten wordt de waarde NIL gebruikt om het einde van de +lijst aan te geven (je moet de pointer(s) zelf die waarde +geven; standaard staat er alleen onzin in). + +Rudy Oppers diff --git a/sunrise_special/1/recursief_programmeren.md b/sunrise_special/1/recursief_programmeren.md new file mode 100644 index 0000000..7997be8 --- /dev/null +++ b/sunrise_special/1/recursief_programmeren.md @@ -0,0 +1,150 @@ +# R E C U R S I E F P R O G R A M M E R E N + + +Dit is een onderwerp waar de gemiddelde MSX'er niet veel van +zal weten, maar dat toch buitengewoon interessant is. Het is +een programmeertechniek die al ontwikkeld is voordat het in +werkelijkheid gebruikt kon worden (lees: computers genoeg +geheugen hadden). + + +## D E T E C H N I E K + +Een recursieve routine is een routine die zichzelf aanroept. +Dit klinkt mischien een beetje vreemd, maar het is best +handig. Je zou je een routine voor kunnen stellen die op een +gegeven moment gegevens nodig heeft die met dezelfde routine +gevonden kunnen worden. + +Een voorbeeld: + +Stel je hebt een touw dat x meter lang is en je wilt dit +touw in stukjes van 1 en 2 meter gaan verdelen. De vraag is +nu op hoeveel manieren dit kan bij een gegeven x. + +Bij een lengte x=20 meter is dit al heel moeilijk te vinden, +maar bij een lengte van 2 meter is het aantal manieren +gelijk aan x, nl. 2. + +x = 2 meter => Manieren: 11 + 2 + Het kan dus op twee manieren. +x = 1 meter => Manieren: 1 + Het kan dus op 1 manier. + +Dit zijn twee gevallen waarbij het aantal manieren gelijk is +aan het aantal meter touw en dat is een heel belangerijk +gegeven. + +x = 4 meter => Manieren: 1111 + 112 + 121 + 211 + 22 + Het kan hier op 5 manieren. + +Met een beetje inzicht in getallen kan je afleiden dat het +aantal mogelijkheden bij x=4 gelijk is aan: + +Mog (x=4) = Mog.(x-2) + Mog.(x-1) + = 2 + 3 + = 5 + +Het aantal mogelijkheden bij x=3 is ook gelijk aan het +aantal meters lengte, maar dat is puur toevallig en verder +niet van belang. + +Wat we nu hebben gezien is dat we het aantal mogelijkheden +kunnen onderverdelen in deelprobleempjes en die op hun beurt +ook weer in deelprobleempjes, net zolang tot we een +deelprobleem hebben waarvan we het antwoord al weten. + +Nu is het mogelijk om dit in programmacode te schrijven. Ik +zal dat in de taal C doen omdat mijn PASCAL naar de +achtergrond is gezakt sinds ik met C werk. + +int aantal_mog(int x) +{ +if (x <= 2) /* Dit is de luie regel (zie verder) */ +return x; +else return aantal_mog(x-2) + aantal_mog(x-1); +} + +Dit stukje programma zal zelfs voor mensen die nog nooit een +regel C gezien hebben wel te begrijpen zijn. De parameters +die achter de 'return' opdracht staan zijn de parameters die +aan de vorige routine teruggegeven worden. In assembly +gebeurd dit met CALL en RET. + +De 'luie regel' is de regel die het werk in deelproblemen +verdeelt en die het vereenvoudigde probleem doorgeeft. Dit +programma is echter zo kort dat de luie regel meteen ook de +enige regel van de hele routine is. + +Het 'else' gedeelte geeft het deelprobleem door aan de +volgende routineaanroep. De 'return x' geeft een waarde van +x terug die we van tevoren al wisten (x <= 2). Ik kan het me +heel goed voorstellen als dit alles maar moeilijk te +bevatten is, maar het klopt toch allemaal echt. + + +## V O O R - E N N A D E L E N + +Het allergrootste voordeel van recursief programmeren is dat +het extreem weinig programmacode oplevert. Ik daag u graag +uit om dit probleem zonder recursie op te lossen. Het is +vast wel mogelijk, maar het wordt dan wel een heel lang +programma met heel veel sprongen en andere onoverzichtelijke +ellende. + +Nog een voordeel is dat zodra je recursie onder de knie hebt +(lees: zelf een paar keer doen) het heel eenvoudig is. De +probleemomschrijving lijkt nl. al heel veel op de feitelijke +programmacode en dus is het omzetten een makkie. + +Het grootste nadeel van recursie is dat - alhoewel de +routines zelf heel weinig geheugen nodig hebben - ze tijdens +executie enorme stukken werkruimte op kunnen slokken. In een +situatie waar je probeert om voor x=500 in te vullen zal je +wel begrijpen dat er extreem veel deelproblemen zullen +ontstaan die allemaal stackruimte nodig hebben om hun +terugkeeradres op te zetten. Zo heb je voor 10000 CALL +instrukties in assembly een stack nodig met een lengte van +20000 bytes en geloof me, dat haal je met deze methode +makkelijk. + +Dit is ook meteen de reden waarom ik niet een uitgewerkt +assembly programma gebruik. Het is op een MSX gewoon niet +praktisch omdat je meestal maar 64 kB direkt adresseerbaar +geheugen hebt waarvan meestal de helft voor het operating +system is en dan praten we nog niet eens over eigen +programma's. Dit artikel is daarom ook meer van informatieve +dan van praktische aard voor MSX omdat ook C op MSX een ware +ramp is (programmatechnisch gesproken dan). + + +## C O N C L U S I E + +Het zal sommige mensen wel niet aanstaan, maar voor dit +soort dingen heb je toch snel een PC of Atari nodig (werkt +heel lekker met C) omdat die veel meer direkt adresseerbaar +geheugen hebben en omdat die hardware veel geschikter is +voor een taal als C. Een recursie toepassing in assembly is +af te raden omdat dat behoorlijk moeilijk is terwijl je in C +feitelijk het probleem letterlijk over kunt tikken. + +Affijn, recursie is een heel interessante programmeermethode +met vele mogelijkheden zoals sorteren of het beheren en +onderhouden van boomstrukturen (waar ik ook nog wel eens +over kan schrijven omdat dat dingen zijn die prima in +assembly kunnen.) Een andere leuke toepassing van recursie +is bv. het probleem van de torens van Hanoi, maar dat is op +dit moment iets te ingewikkeld om hier te behandelen. + +Recursie is een veel gebruikte methode maar wordt voor de +meeste mensen pas interessant op het moment dat ze +professioneel met computers aan de gang gaan. Het is daarom +voor deze mensen gewoon leuk om alvast eens met deze +techniek in aanraking te komen. + +Alex van der Wal diff --git a/sunrise_special/1/rel_assembleren.md b/sunrise_special/1/rel_assembleren.md new file mode 100644 index 0000000..4b2f2e8 --- /dev/null +++ b/sunrise_special/1/rel_assembleren.md @@ -0,0 +1,173 @@ +# R E L O C A T A B L E A S S E M B L E R E N + + +Eerst even dit: ik ga bij dit stukje uit van de GEN80 +assembler en de L80 linker. Omdat deze programma's onder DOS +draaien, gaat het hier dus ook automatisch over '.COM'-files +als resultaat. + +Naast GEN80 kun je bijvoorbeeld ook met M80 en RMAC reloca- +table assembleren. + + +## N O R M A A L A S S E M B L E R E N + +Veel mensen die wel eens iets in machinetaal doen, schrijven +hun listing als een lange lijst met instructies. Het +assembleren kan, vooral bij de wat grotere programma's, best +lang duren. De assembler moet immers die hele lap tekst van +een schijf lezen. + +Na het testen kom je er nog wel eens achter dat iets niet +helemaal goed werkt, en je gaat aan het foutzoeken... Na +lang zwoegen is de plaats waar de fout zich bevindt waar- +schijnlijk gevonden. Verandering aanbrengen en opnieuw +assembleren. + +De assembler moet nu die hele lap tekst (ook de foutloze +delen) opnieuw verwerken. Dit kost weer een hoop tijd. + +Dit proces herhaalt zich tot het moment dat de programmeur +denkt dat alle fouten uit het programma zijn verwijderd. + +Doordat iedere keer dat je de listing assembleert de hele +programmatekst moet worden verwerkt kan dit, vooral bij +lange listings, enorm veel tijd kosten. + + +## R E L O C A T A B L E A S S E M B L E R E N + +Maar het kan ook anders, en dat anders heet 'relocatable' +assembleren. + +Hierbij maak je gebruik van korte deelprogramma's +waarin allerlei subroutines staan. Die losse delen kun je +dan apart van elkaar assembleren en later aan elkaar plakken +met een linker (dit is een apart verkrijgbaar programma). + +In die losse delen zit de grote kracht van het relocatable +assembleren. Als je bij het foutzoeken een fout ontdekt, dan +hoef je niet weer die hele lijst door te spitten en te +assembleren, maar slechts een klein stukje van het hele +programma. Omdat je nu maar een stukje van het geheel door +de assembler haalt, bespaar je veel tijd (de andere modules +zijn immers niet veranderd, dus die hoef je nu dan ook niet +opnieuw te assembleren). + +Ook kun je met deze modulaire opzet modules die je eerder +hebt geschreven opnieuw gebruiken in je volgende program- +ma's. Je kunt zo dus een bibliotheek van kant en klare +modules opbouwen. + + +## W E R K W I J Z E + +Bij relocatable assembleren ga je er van uit dat een lang +programma op te splitsen valt in kortere delen, die als het +even kan ook nog min of meer iets met elkaar te maken hebben +(een soort van bibliotheek-bestanden dus). + +Als je een zo'n module geschreven hebt, dan kun je hem as- +sembleren. + +In de relocatable mode gaat een assembler heel anders om met +adressen. Hij ziet de adressen nu niet als een echt getal, +maar als een offset. De echte adressen worden pas later +ingevuld. + +Je krijgt nu ook geen '.COM'-files, maar '.REL'-files, wat +staat voor 'relocatable'. + +Na het schrijven van de modules en het assembleren ervan, +kun je alles aan elkaar gaan knopen, het 'linken'. Dit +linken gebeurt met een apart programma, de linker (bij- +voorbeeld LINK.COM of L80.COM). + + +## H E T L I N K E N + +Bij dit 'linken' geef je op welke modules je aan elkaar wilt +koppelen. Daarna geef je de naam van het uiteindelijke +programma op et voila! Je hebt je programma.... + +Met l80 gaat dit linken als volgt: + +A>l80 module1,module2,module3,prognaam/n/e + +De linker laadt nu de bestanden module1.rel, module2.rel en +module3.rel van disk. Ze komen ook in die volgorde in het +uiteindelijke programma te staan, dus je kunt niet zomaar +bij een module beginnen! In dit geval begint de programma- +uitvoer dus met module1. + +Hierna worden deze modules 'gelinkt'. Dit linken wil zoveel +zeggen als 'zet de genoemde bestanden achter elkaar en vul +waar dat nodig is de juiste adressen in'. Bij het invullen +van adressen worden al de 'offset' adressen vervangen door +absolute adressen. + +Na het linken wordt het gevormde programma op disk gezet. In +het voorbeeld is die naam 'prognaam.com'. Als er '/n' achter +achter een naam staat, gaat de linker er van uit dat dat de +naam van het programma moet worden. + +De '/e' wil zeggen dat de linker na het wegschrijven van +prognaam.com moet stoppen, zodat je weer in DOS zit. + + +## H E T R E S U L T A A T + +Nu heb je een programma op disk staan met de naam +prognaam.com. Het testen kan beginnen. Dit testen bestaat +meestal uit het opstarten van dat programma en proberen of +je je geesteskindje vast kunt laten lopen. + +Als er nu een fout wordt gevonden die bijvoorbeeld in +module2 zit, dan hoef je alleen module2 te veranderen en +opnieuw te assembleren. Bij het linken moet je (uiteraard) +wel weer alle modules opgeven. + +Het is trouwens handig als je de assembleeren link-opdracht +in een batchfile zet. Dat kan veel tikwerk schelen (en het +werkt wat vriendelijker). + +Zo'n batch ziet er dan bijvoorbeeld zo uit: + +gen80 %1 +l80 init,commando,diversen,edit,drawscr,getconv,monitor/n/e + + +## A S S S E M B L E R O P D R A C H T E N + +Een assembler die in een relocatable mode kan worden gezet, +kent een aantal speciaal op die mode gerichte opdrachten. + +Zo heb je bij GEN80 o.a. de directives external en public. +Er zijn er nog wel meer die met de relocatable mode te maken +hebben, maar dat staat allemaal in de handleiding van je +assembler. + +Je kunt GEN80 laten weten dat je in relocatable mode wilt +assembleren door op de eerste regel van je programma * R+ te +zetten. + +Het kan natuurlijk ook door gen80ins op te starten en die +relmode vast in het programma te zetten. Als je nu iets in +de absolute mode wilt assembleren, dan kun je dat doen door +op de eerste regel * R- te zetten. + + +## V O O R B E E L D + +Op deze disk staan als voorbeeld 3 modules (.GEN) en hun ge- +assembleerde vorm (.REL en .SYM). +De listings bevatten volop commentaar, dus bekijk ze eens... + +Ik heb ook het gelinkte programma bijgevoegd (RELADEMO.COM). +Het programma geeft een piepje, wacht op een toetsdruk en +drukt als laatste 20 keer het ingedrukte teken af. Op zich +niet echt nuttig, maar het gaat dan eigenlijk ook om de +listings. + + +Rudy Oppers diff --git a/sunrise_special/1/set_scroll_in_basic.md b/sunrise_special/1/set_scroll_in_basic.md new file mode 100644 index 0000000..cf0c27a --- /dev/null +++ b/sunrise_special/1/set_scroll_in_basic.md @@ -0,0 +1,108 @@ +# S E T S C R O L L I N B A S I C + + + +## I N L E I D I N G + +Op een MSX2+ kan (in BASIC) m.b.v. het SET SCROLL commando +een vrijwel vloeiende scroll beweging krijgen. Omdat niet +iedereen zelf een vloeiende scroll in BASIC of in ML kan +programmeren, leg ik in deze tekst uit hoe je heel +gemakkelijk het SET SCROLL commando kunt gebruiken. + + +## S E T S C R O L L + +Het SET SCROLL commando kan je in alle schermen gebruiken, +behalve in SCREEN 0. Bij gebruik van het SET SCROLL commando +in SCREEN 0 gaat het naar boven scrollen niet hetzelfde als +in de grafische schermen. Bij deze tekstschermen gaat de +tekst of eventueel tekening niet omhoog maar scrollt met +rijen van acht hoog, (dat is dus het formaat van de ASCII +karakterset), daar wil ik mee zeggen dat alles wat boven aan +het blok van acht hoog verdwijnt, er aan de onderkant weer +bij komt. + +In de grafische schermen scrollt het hele beeld wel goed +maar krijg je het sprites-blok te zien. Daar heb ik wel een +truukje voor maar dat komt later. + + +## G E B R U I K + +Het gebruik is eigenlijk heel gemakkelijk, je hoeft namelijk +alleen het commando plus een getal voor de horizontale +scrolling en een getal voor de verticale scrolling in te +voeren. B.v. Set scroll 2,4 betekent dat je 2 pixels +horizontaal en 4 pixels verticaal scrollt. + +Overigens mag je geen negatieve (dus min) getallen in +voeren. Dat is ook niet nodig want als je in grafische +schermen SET SCROLL 0,0 in voert geeft dat het zelfde +resultaat als SET SCROLL 256,0 (voor SCREEN 6 en 7 dus SET +SCROLL 512,0), alleen is het scherm bij SET SCROLL 256 (of +512),0 een keer helemaal rond geweest. Zo kan je dus ook met +een lus optellen van 0 tot 255 (of 511) en ook aftellen van +255 (of 511) tot 0. Dat laatste geeft dus een scroll naar +links en de eerste naar +rechts. Zo werkt dat ook met het verticaal scrollen. + + +## V D P ( 1 9 ) E N V D P ( 2 4 ) + +Het set scroll commando komt overeen met VDP(19) (of set +adjust) en VDP(24). VDP(19) geeft namelijk een soort van +horizontale scroll net als set scroll X,0. Hier staat X voor +een getal. Er is wel een groot nadeel aan VDP(19) namelijk +dat de getallen die je in kunt voeren van -7 tot +8 lopen. +En met VDP(19) kan je een horizontale EN verticale scroll +maken. Dan nu VDP(24), dit komt volkomen overeen met het +getal dat je in voert bij set scroll voor verticaal +scrollen. Je kunt ook getallen van 0 tot 255 invoeren en +zelfs het spritesblok komt ook mee. Hieronder heb ik een +klein tabelletje neergezet waarin je kunt zien waarmee SET +SCROLL overeenkomt, zoals je ziet is verticaal scrollen +hetzelfde als VDP(24). + + HORIZONTAAL -- VERTICAAL +------------------------------------------------- +|SET SCROLL | GETAL 0 TOT 255 | GETAL 0 TOT 255 | +|-----------|-----------------|-----------------| +| VDP(19) | GETAL -7 TOT +8 | GETAL -7 TOT +8 | +|-----------|-----------------|-----------------| +| VDP(24) | N.V.T. | GETAL 0 TOT 255 | +------------------------------------------------- + + +## V O O R B E E L D + +Dan nu maar even een klein voorbeeld programaatje. Met de ' +geef ik wat kommentaar. Bedenk wel dat dit programmaatje +ALLEEN voor MSX2+ bedoeld is. +``` +; Dit programma is alleen voor grafische schermen 5 en 8 + +10 COLOR 15,0,0:SCREEN X ' VUL HIER VOOR X IN 5 OF 8 +20 SET PAGE 1,1:CLS:COPY (0,0)-(256,64) TO (0,212) +30 VDP(9)=VDP(9) OR 2 'LAAT DE SPRITES NIET ZIEN +40 OPEN "GRP:" FOR OUTPUT AS #1 +50 PSET (200,200):PRINT #1,"MSX 2+" +55 ' _TURBO ON 'GEBRUIK ALLEEN MET _BC +60 X1 = 1:Y1 = 1 +70 X2 = X2+X1:IF X2 > 245 THEN X1 = -1 'X2>245 ? JA,DAN -1 +80 Y2 = Y2+Y1:IF Y2 > 200 THEN Y1 = -1 'Y2>200 ? JA,DAN -1 +90 IF X2<15 THEN X1 = 1 'X2<15 ? JA,DAN +1 +100 IF Y2<50 THEN Y1 = 1 'Y2<50 ? JA,DAN +1 +110 SET SCROLL X2,Y2 'SCROLLEN +120 IF INKEY$="" THEN GOTO 70 ELSE END +``` +Je kan eventueel nog _BC gebruiken en dan in regel 55 het +rem (') teken weghalen. Als je het programma RUNt zie je de +tekst MSX 2+ over het beeld schuiven, de tekst gaat ook door +het beeld (dus links eruit en rechts erin). Maar er is geen +sprites blok te bekennen. + +Veel plezier met het SET SCROLL commando en misschien de +volgende keer een complete tekstzoek routine met scroll. + +Bart Schouten diff --git a/sunrise_special/1/te_zachte_psg_bij_de_nms_8250_55_80.md b/sunrise_special/1/te_zachte_psg_bij_de_nms_8250_55_80.md new file mode 100644 index 0000000..a24da1c --- /dev/null +++ b/sunrise_special/1/te_zachte_psg_bij_de_nms_8250_55_80.md @@ -0,0 +1,36 @@ +# T E Z A C H T E P S G B I J D E N M S 8 2 5 0 / 5 5 / 8 0 + + +Vaak is het zo dat de PSG wegvalt door het gebruik van een +FM-PAK op de NMS 8250/55 en 80. Dit is jammer, want de +PSG-drums zijn vaak onmisbaar bij FM-PAK songs! + +Nu kan je dit probleem heel gemakkelijk oplossen. Men heeft +hier het kabeltje dat bij de PAK wordt geleverd voor nodig. +(van koptelefoon naar 1 tulpstekker). Druk nu de tulpstekker +in de monitor (AUDIO ingang) en de koptelefoon in de +buitenste uitgang van de FM-PAK, nu wordt de PSG door de +monitor gespeeld, maar de PAK muziek niet, deze zul je door +een versterker moeten laten weergeven. + +In mijn geval was dit een PSEUDO-STEREO versterker. Om de +PAK muziek door de versterker te laten klinken, heb je een +stekkerkabel nodig, met tenminste 1 tulpstekker, voor in de +AUDIO uitgang van de MSX. Aan de andere uiteinde zal een +stekker moeten zitten die in je versterker/installatie past. +Meestal is dit ook een tulpstekker (soms ook 2) + +Als alles goed is gegaan zal nu de PSG samen met de FM-PAK +te horen zijn, welliswar gescheiden, maar toch... + +Voor meer details kun je het beste even de file +"ZACHTPSG.PCT" inladen in Dynamic Publisher. Hierin staat +alles nog eens in een handig schema uitgelegd. + +Mocht je ondanks nog vragen hebben, bel dan eens met BBS +SUNRISE NOORD (dagelijks 22-7, tel: 05126-2123 of gewoon +spraak na 18:00 uur, vragen naar Haiko...) + +Veel luisterplezier, + +Haiko de Boer diff --git a/sunrise_special/1/track_0_op_de_turbo-r.md b/sunrise_special/1/track_0_op_de_turbo-r.md new file mode 100644 index 0000000..07873fb --- /dev/null +++ b/sunrise_special/1/track_0_op_de_turbo-r.md @@ -0,0 +1,78 @@ +# T R A C K 0 O P D E T U R B O R + + +Het zal veel MSX turbo R bezitters al zijn opgevallen dat de +diskdrive veel meer geluid produceert bij het lezen of +schrijven van track 0 dan bij het lezen of schrijven van +andere tracks. Waarom is dat zo? + + +## B E L A N G R I J K E I N F O R M A T I E + +Track #0 bevat de logische sectoren #0 tot en met #17. +Sector #0 tot en met #8 op kant #0 en sector #9 tot en met +#17 op kant #1. Zoals u weet (of anders in de diskcursus op +deze Special kunt lezen) staat in deze sectoren zeer +belangrijke informatie, namelijk de bootsector, de FAT en de +directory. + +Deze informatie is zeer belangrijk voor het functioneren van +de diskette. Raakt deze informatie beschadigt, dan is de +informatie op de rest van de diskette slechts met grote +moeite bereikbaar. Vandaar dat het een absolute ramp is als +een van de sectoren #0 t/m #13 beschadigd raakt. + +## B U I T E N S T E T R A C K + +Een oplossing die bij alle computers gebruikt wordt, is het +feit dat track 0 de buitenste track is. Van binnen naar +buiten toe worden de tracks steeds groter, terwijl er toch +steeds dezelfde informatie op staat. U begrijpt dat er +minder storingen optreden indien de informatie verder uit +elkaar staat. Daarom is het beter om voor de zo belangrijke +track 0 de buitenste track te gebruiken. + + +## E X T R A V E I L I G + +Bij het ontwikkelen van de turbo R vond men dit blijkbaar +nog niet genoeg, want op de turbo R krijgt track 0 een +speciale behandeling, die nog veiliger is. + +Ik weet niet precies wat deze speciale behandeling doet, +maar vast staat dat het herrie maakt! Veel extra tijd kost +het echter niet, het verschil in snelheid tussen het inlezen +van track 0 en een willekeurige andere track is nihil. + + +## E I G E N L I J K S T I L + +De diskdrive van de turbo R is eigenlijk erg stil. Zelfs +diskettes die op mijn vorige computer (een Sony HB-F700P +MSX2) "aanliepen" werken nu geruisloos. Behalve bij track 0 +dan natuurlijk. + +Je kan het goed merken als je een diskette met een sector- +kopieerprogramma kopieert. Aan het begin wordt track 0 +gelezen, dat maakt herrie, en daarna hoor je bijna niets +meer. Alleen het "overstappen" van de kop van de diskdrive +naar een andere track is te horen door een klein tikje. +Verder is de diskdrive zeer stil! + +Maar bij het inlezen/wegschrijven van files produceert de +turbo R wel redelijk wat geluid. Dit komt omdat de meeste +files niet al te lang zijn, en dus de voornaamste tijd in +beslag wordt genomen door het lezen van de directory en de +FAT. En dat maakt nou precies die herrie... + + +## B E T R O U W B A A R + +Ik neem het geluid voor lief, want de diskdrive van de turbo +R is wel zeer betrouwbaar. Ik heb mijn turbo R al bijna een +jaar, maar heb nog nooit last gehad van kapotte sectoren in +de FAT of directory. Bij mijn vorige computer kwam dat wel +zo af en toe voor. Blijkbaar helpt die speciale behandeling +uitstekend! + +Stefan Boer diff --git a/Sunrise Special/2/CDD.md b/sunrise_special/2/CDD.md similarity index 100% rename from Sunrise Special/2/CDD.md rename to sunrise_special/2/CDD.md diff --git a/Sunrise Special/2/Redirection.md b/sunrise_special/2/Redirection.md similarity index 100% rename from Sunrise Special/2/Redirection.md rename to sunrise_special/2/Redirection.md diff --git a/Sunrise Special/2/Blinkmode.md b/sunrise_special/2/blinkmode.md similarity index 100% rename from Sunrise Special/2/Blinkmode.md rename to sunrise_special/2/blinkmode.md diff --git a/sunrise_special/2/cursus_dd-graph.md b/sunrise_special/2/cursus_dd-graph.md new file mode 100644 index 0000000..b68718e --- /dev/null +++ b/sunrise_special/2/cursus_dd-graph.md @@ -0,0 +1,448 @@ +# C U R U S D D - G R A P H + + +DD-Graph is een tekenprogramma dat is ontwikkeld door T&E +Soft, het werkt op een MSX2 en hoger op grafisch scherm 5. +Het programma is volgens mij niet (meer) in Nederland te +verkrijgen maar omdat het programma erg veel gebruikt wordt +en de handleiding in het Japans is heb ik deze cursus +geschreven. (N.B. Omdat het programma erg veel mogelijkheden +bevat en het onmogelijk is het in 16 kB helemaal uit te +leggen, is dit artikel in 2 delen, nl. DD-GRAPH -1- en -2- +terug te vinden in het submenu. + +We zullen maar beginnen bij het begin en dat is bij het +opstart-menu, hier kan worden gekozen tussen: AGE, het +SCREEN 5 tekenprogramma en SPEN, het sprite ontwerp- +programma. Wij beginnen met de bovenste keuze en dat is AGE +(de tweede keuze is SPEN en de derde is terug naar DOS.) + + +## A G E + + + +### S P E C I A L E T O E T S E N + +(Even van te voren, als ik het over de rechter en linker +muisknop heb, is dat hetzelfde als F1 en F2.) + +Als AGE is opgestart verschijnt er een pijltje in het beeld +dat kan worden bestuurd met de muis in poort 1 of met de +cursortoetsen. Als er voor de cursor toetsen wordt gekozen +zijn er twee extra toetsen nl. [SELECT] en [SHIFT]. Met +[SHIFT] gaat het pijltje iets sneller en met [SELECT] +beweegt het pijltje in blokken. De [SHIFT] functie werkt +overigens ook met de muis. + +De muis en de cursors kunnen ook tegelijker tijd worden +gebruikt. Als de muis niet in poort 1 zit en AGE is al +opgestart moet de muis in poort 1 gestopt worden en op de +[STOP] toets gedrukt worden, nu herkent AGE de muis wel! Als +men met de cursors werkt komen de functietoetsen F1 en F2 +overeen met respectievelijk de linker en rechter muisknop. + +De functietoets F5 zorgt voor een COLOR=NEW, d.w.z. dat het +palet weer op de standaard kleuren wordt gezet. Met de [ESC] +toets neemt men de kleur waar het pijltje tijdens het +indrukken van de [ESC] opstond. Als men de rechter muisknop +indrukt en ingedrukt houd en daarna de linker muisknop in +drukt en vervolgens de muisknoppen tegelijkertijd(!) los +laat geeft dit hetzelfde effect als de [ESC] toets. Met de +CTRL toets en de cursor toetsen kan men het beeld centreren. + +Het kleurenpalet kan worden verplaatst door op het witte +blokje boven het palet te gaan staan en dan op de linker +muisknop te drukken en vervolgens het palet op de gewenste +plaats te zetten en nogmaals op de linker muisknop te +drukken. Als men het palet helemaal wil laten verdwijnen +moet men met het pijltje op hetzelfde witte blokje gaan +staan en dan de linker muisknop indrukken (en ingedrukt +houden) en vervolgens de rechter muisknop ook indrukken en +tegelijkertijd(!) loslaten. + +Met de [GRAPH] toets kan men het submenu laten zien van de +laats gekozen functie. Met de cijfertoetsen 1 tot en met 3 +kan men pagina 1 tot en met 3 laten zien (waar dit voor is +leg ik de volgende keer wel uit!). Er kan NIET op deze +schermen gewerkt worden, althans U kunt niet een stip op een +pagina neerzetten waar U de cijfertoets van ingedrukt houdt, +de stip zal gewoon op de huidige pagina worden gezet!!! + +Ik denk dat ik nu wel alle speciale toetsen en +toetscombinaties heb genoemd, omdat het er veel zijn maak er +even een overzicht van (handig voor een screendump!). +cOVERZICHT. + +Toets of toetscombinatie: Uitwerking : +------------------------------------------------------------- +SELECT.................... Pijltje beweegt in blokken. +------------------------------------------------------------- +SHIFT .................... Het pijltje beweegt sneller. +------------------------------------------------------------- +STOP ..................... Muis in poort 1 aangesloten ? +------------------------------------------------------------- +F-1 ...................... Hetzelfde als de linker muisknop. +------------------------------------------------------------- +F-2 ...................... Hetzelfde als de rechter muisknop. +------------------------------------------------------------- +F-5 ...................... Geeft een color=new. +------------------------------------------------------------- +ESC of de R+L muisknop ... Kleur waar pijltje opstaat=actief. +------------------------------------------------------------- +CTRL + CURSORS ........... Centreren beeld. +------------------------------------------------------------- +Linker muisknop op blokje. Verplaatsen van kleuren palet. +------------------------------------------------------------- +Beide muisknoppen op blok. Verwijderen palet. +------------------------------------------------------------- +GRAPH .................... Show laatst gekozen functie+menu. +------------------------------------------------------------- +Cijfertoetsen 1 t/m 3 .... Laten zien van de pagina's 1,2,3. +------------------------------------------------------------- + +Dan zal ik nu de 16 functies gaan bespreken uit het +menu-balkje onderin het menu. (Zie ook het tweede deel van +deze tekst in het submenu genaamd: DD-GRAPH -2-.) + + +### D E F U N C T I E S + +De eerste functie: L I N E , (helemaal linksonder) als we +deze functie kiezen met de linker muisknop dan kunnen we +gewoon lijnen trekken die niet aan elkaar vast zitten. Als +we echter op het icoon op de rechter muisknop drukken komen +we in een submenu, hier kunnen we kiezen uit conected line +en radial line. De eerste keuze trekt lijnen die wel aan +elkaar vast zitten d.w.z. waar de ene lijn stopt begint de +andere. De tweede keuze trekt lijn vanuit een punt, een +zogenaamd waaier-effect. + +De tweede functie: D R A W , (rechts naast LINE) nadat we +met de linker muisknop op dit icoon hebben gedrukt kunnen we +vervolgens met de hand tekenen. Als we echter op de rechter +muisknop drukken komen we in het submenu en kunnen we kiezen +of we met een patroon willen tekenen of met gewone lijnen, +als het rondje ingekleurd is tekenen we wel met het gekozen +patroon en anders niet. + +De derde functie: B O X , (rechts naast DRAW) deze functie +spreekt voor zich. Hiermee kunnen we rechthoeken maken maar +ze worden NIET ingekleurd. + +Nu wordt het wat ingewikkelder, als we nl. op de rechter +muisknop drukken met het pijltje op het BOX icoon, komen we +in een submenu waar de stappen die de MUIS moet maken, +kunnen worden ingevuld. Dit werkt als volgt: we zien twee +pijltjes naar rechts en twee naar links, ook zien we twee +pijltjes naar links met een streep erachter. Met de pijltjes +naar links en naar rechts kunnen de stappen met 1 stap +verhoogd en met 1 stap velaagd worden. Met de pijltjes met +de streep erachter kunnen de stappen alsvolgt verhoogd +worden: 2, 4, 8, 16, 64, 128 enz. Ook kunnen de stappen weer +hersteld worden d.m.v. CLEAR. (N.B. stappen is erg +gemakkelijk als je b.v. een karakterset van 16x16 moet +tekenen, dan neem je gewoon de stappen 16 en 16.) + +De vierde functie: B O X F I L L , (rechts naast BOX). BOX +FILL werkt hetzelfde als BOX alleen het vierkant wordt WEL +ingekleurd. Ook is het submenu hetzelfde als bij BOX. + +De vijfde functie: C O P Y , (rechts naast BOX FILL). Met +COPY kan je gewoon delen van de pagina kopi�ren naar een +andere plaats. Er zijn daar 4 manieren voor: 1 XOR, 2 OR, 3 +TPSET en 4 SWAP, deze zijn te kiezen door het submenu op te +roepen op de bekende manier en daar aan te klikken wat men +wilt. Met XOR en OR worden de kleuren respectievelijk +ge'XOR'd en ge'OR'd. Met TPSET (TIMP) kan er worden +gekopieerd maar kleur 0 is doorzichtig, dus je beschadigt +het deel waarover je met kleur 0 kopieert niet! Dan is er +nog SWAP, met SWAP verplaats je de gekopieerde vlakken. Dus +alles dat onder het blok zat wat je kopieerde wordt +verplaatst naar de plek waar je vandaan kopieerde. + +De zesde functie: P A I N T , (rechts naast COPY). Deze +functie spreekt ook voor zich. Er kunnen gewoon stukken of +het hele scherm worden ingekleurd met de gekozen kleur. Er +zit geen optie achter het submenu, alleen wat info over AGE +en een klok. + +De zevende functie: C I R C L E , (rechts naast PAINT). +Nadat deze functie is gekozen kan je door een druk op de +linker muisknop het middenpunt van de cirkel bepalen. Nu de +grootte bepalen en nog een keer op de linker muisknop +drukken, klaar is kees. Er is ook bij deze functie geen +submenu. + +De achtste functie: T U R N , (rechts naast CIRCLE) is erg +handig om tekeningen of delen daarvan horizontaal of +verticaal te keren, het is dus mogelijk om b.v. de tekts +"HALLO" horizontaal te keren en dan staat er "OLLAH". De +richting van het keren wordt bepaald door het aanklikken van +1 van de pijltjes naast het palet. Geen submenu aanwezig. + +De negende functie: R O L L , (rechts naast TURN) werkt ook +met de pijltjes naast het palet. Met ROLL kun je een deel +van een tekening verschuiven, er verandert dus niets alleen +de plaats. Geen submenu aanwezig. + +De tiende functie: T R A N S , (rechts naast ROLL) en alweer +de pijltjes om te besturen. Met TRANS kunnen delen van een +tekening worden gedraaid, d.w.z. dat een horizontale +tekening verticaal kan worden gemaakt en andersom. Er is +echter een voorwaarde, het vlak dat je wilt "TRANS'EN" moet +vierkant zijn! Dus als je een langwerpig vlak hebt ben je +verplicht een heel ruim vlak te nemen. En helaas weer geen +submenu. + +De elfde en voor dit gedeelte laatste functie: 2 C O P Y . +Met deze functie kan je kleine vlakken vergroten en +andersom. Het werkt alsvolgt: je bepaald het gebied dat je +groter of kleiner wilt maken en daarna bepaal je de plaatsen +grootte van het plaatje, simpel toch?! Deze functie heeft +ook geen submenu. + +De twaalfde functie: Z O O M , (rechts naast 2COPY). Dit is +waarschijnlijk de meest gebruikte tekenfunctie maar is +daarentegen niet ingewikkeld! Na een druk op de rechter +muisknop kunnen we kiezen of we een loupe en/of een zoom +grid willen gebruiken. Zoom grid zijn ruitjes die over de +vergrote tekening worden gezet waarbij het tellen van hokjes +makkelijker wordt. Loupe is het blokje dat meestal in beeld +is wanneer er een functie is gekozen met de linker- +muisknop. In dit blokjes staat een vergroot beeld van de +plaats waar de pijl zich bevindt en de ruimte daar om heen, +voor de rest staan er de x positie en de y positie van het +pijltje, de kleur die zich momenteel onder het pijltje +bevindt en de nu actieve functie. + +Met de linker muisknop word er een deel van het beeld +vergroot weergegeven in een speciaal blok, in dit blok staan +bovenaan de kleuren 0 tot en met 15, in het midden staat het +vergrote blok en onder kan de keuze gemaakt worden of men +2x, 4x, 8x of 16x wil vergroten, ook kan het blokje met de +pijltjes verplaatst worden. Wanneer men op het vierkantje +gaat staan (wat om het normale scherm staat) en daarna op de +linker muisknop drukt, kan het vierkant verplaatst worden +over het hele scherm. Om hierna weer te vergroten drukt men +nogmaals op de linker-muisknop. + +De dertiende functie: C O L O R , (rechts naast ZOOM). Na +een druk op de linker muisknop, kunt u een bepaalde kleur in +het door u aangegeven vlak, vervangen door een andere kleur. +Teken een rechthoek, selecteer een kleur uit het palet en +wijs een kleur aan binnen de rechthoek. + +Als we op de rechter muisknop drukken komen we in het +submenu en hier kan het palet worden veranderd. Ik zal het +hele kleuren menu even van links naar rechts behandelen. +Helemaal links-boven staat COL=X dat is het huidige +kleurnummer (X loopt van 0 tot 15). Hieronder staat de kleur +van het huidige kleurnummer, dus dit blokje is blauw bij +kleurnummer 4, mits het standaard palet is ingesteld (F5!). +Dan volgt R, G en B onder elkaar, waar de waardes ingesteld +kunnen worden d.m.v. de blokjes. + +Een druk op de linker muisknop en het van links naar rechts +bewegen van de muis verandert de waarde. Hierna een rondje +met PAL(X) en een met INITIAL. Met PAL(X) kan worden +ingesteld of U palet 1 of 2 wilt veranderen. Wanneer U b.v. +kleurnummer 1 rood maakt in palet 1 en in palet 2 blauw, dan +zal, wanneer U op de rechter-muisknop drukt, de kleur 1 +overlopen van rood naar blauw en terug! + +Met INITIAL wordt palet 2 gelijk aan palet 1 gemaakt. Dan +volgen de kleuren 0 tot en met F (15 dus). In plaats van de +kleur aangeven in deze kleurenbalk kan U ook op COL=X gaan +staan en op de linker-muisknop drukken het kleurnummer zal +automatisch met 1 worden verhoogd. + +De veertiende functie: A N I M A T I O N , (rechts naast +COLOR). Hiermee kan een slide-show ofwel en animatie gemaakt +worden. Het werkt als volgt. U tekent een bal, of meerdere, +en drukt op de linker-muisknop wanneer het pijltje zich op +de Japanse tekens bevindt (de 14e functie dus, animation). + +Nu komt er een blokje in beeld met daarin START, END, DEL, +CLEAR en een SPEED regelaar. Nu zet U een vierkantje om het +balletje heen en zet deze willekeurig in het beeld, als U nu +maar 1 balletje hebt getekend dan klikt U nogmaals op de +linker-muisknop nadat U het vierkantje weer om het balletje +hebt gezet. Als U nu, onder de plaats waar U daarnet een +vierkantje hebt gezet, nog een vierkantje zet en daarna op +start drukt, zal U zien dat het balletje heen en weer +beweegt. (Zeer schokkerig, daarom is het aangeraden heel +veel vierkantjes neer te zetten!) + +Met SPEED kunt u nu de snelheid bepalen. Met END stopt de +animatie weer. Als U meerdere balletjes hebt getekend, b.v. +balletjes die ronddraaien, zet U een vierkantje om het +eerste balletje, plaats die in het beeld. Daarna zet U een +vierkantje om het tweede balletje, plaatst die op het eerste +en doet dit vervolgens bij alle balletjes. Na het STARTen +draait het balletje rond. Met DEL wist U een animatie en met +CLEAR de hele animatie. Animatie worden samen met de +tekening op DISK GESAVED dit kost overigens GEEN extra +ruimte! Wanneer u een animatie heeft die zeer snel moet +bewegen kunt u in het submenu kiezen voor HIGH SPEED +ANIMATION. + +De vijftiende functie: F I L E M O D E , (rechts naast +ANIMATION) is een zeer uitgebreide functie, ik zal proberen +het in deze tekst na te maken en daarna uit te leggen +waarvoor alles dient. Na een druk op de linker-muisknop +krijgt u: + +DISK SAVE | NAME[ . ] | DISK LOAD |ABCD|*.*|BAK +MEM SAVE | DELETE | MAKE | GE5| MEM LOAD | FILES |v^ + +Disk save - om tekeningen of delen daarvan op disk weg te + schrijven +Mem save - om tekeningen in het geheugen te bewaren (page1) +Name - om de naam in te voeren, via toetsenbord of via + monitor +Delete - om bestanden te wissen (hoeven geen AGE + bestanden te zijn) +Make - om een kleuren palet weg te schrijven +GE5 - kan worden veranderd in DAT en CMP, DAT voor + COPY files die later in SPEN ingeladen kunnen + worden en CMP voor hele pagina's die gecruncht + weg geschreven worden + GE5 files kunnen gewoon in BASIC ingeladen + worden, dit zijn files die met BSAVE weg + geschreven zijn (met palet, dat kan worden + teruggehaald door een COLOR=RESTORE na het + BLOAD,S commando) +Disk load - idemdito als disk save alleen dan laden +Mem load - idemdito als mem save alleen dan laden + (straks meer hierover!) +ABCD - huidige drive kiezen +*.* - alle files (dus ook niet-AGE files) +BAK - om BACK UP files te zien, wanneer een tekening + onder de zelfde naam wordt gesaved word er auto- + matisch een back up gemaakt, back ups zijn: + GE5BAK.AGE, CMPBAK.AGE en DATBAK.AGE +Pijltjes - om door de files heen te bladeren + +De ruimte onder MEM save is voor de errors en de +bevestigingsvragen. + +Na een druk op de rechter-muisknop krijgt U: + +O Load IMP O Mem Swap O END se sw +O Load timp O Sort dir Swap O Error se sw + +Load IMP - Nadat U een tekening ge'mem-saved' heeft, en een + andere tekening heeft geladen, kunt U nadat U + 'Load IMP' gekozen heeft, delen van de ge'mem- + saved' tekening over de ander laden. Een soort + SUPER-IMPOSED optie dus! Het palet van de laatst + geladen tekening wordt genomen. Voor diegene die + dat willen weten, de ge'mem-saved' tekening komt + terecht op pagina 1. +Load TIMP - Idemdito als Load IMP maar als het deel wat over + de tekening wordt geladen, stukken bevat met + kleur 0 wordt de andere tekening hierdoor zicht- + baar. Kleur 0 is dus doorzichtig. +Mem Swap - De tekening op pagina 1 (zie: Load Imp) wordt + naar de huidige pagina (page 2) gekopieerd en de + tekening die daar al stond word naar page 1 + verplaatst. +Sort dirSw- Ik zou het niet weten, iemand wel? (Nvdr. + Misschien wordt de directory wel gesorteerd als + deze switch wordt aangezet, niet de directory op + disk maar die in het geheugen.) +End se Sw - Het heeft iets met de errors te maken dacht ik. + Maar voor de rest? +Error seSw- Dit is om de herrie en kleurentroep uit te + schakelen, u weet het wel. Als je de diskette + b.v. niet in de drive hebt en dan een tekening + probeert te laden. + +De *.DAT files hebben nog wat extra aandacht nodig, want +wanneer U een DAT file gaat saven zal er altijd een vierkant +ter grootte van SPEN's editor verschijnen. Wilt u echter een +ander formaat saven dan is een klik op de rechter muisknop +voldoende. Hierna kunt u zelf uw blok bepalen. Let wel, Spen +laad alleen het deel dat past in! De *.DAT files zijn +overigens compatible met COPY files in BASIC. + +De laatste en zestiende functie: U N D O , (rechts naast de +FILE MODE). Deze functie is ook wel een install mode. Als u +nl. op de rechter muisknop drukt kunt u instellen of u: + +Auto Change Text Color Swap - wilt oftewel of de kleur van +het menu automatisch op de lichtste kleur gezet moet worden +en de achtergrond op de donkerste. + +Key repeat - Wanneer deze aanstaat zal na het vasthouden van +de linker muisknop, een auto-fire effect bereikt worden. + +MSX-DOS - Terug naar DOS. + +For color - Voorgrond kleur. + +Back color- Achtergrond kleur. + + +Zo, ik hoop dat het u allemaal duidelijk is geworden, hoe +AGE in elkaar zit. Nu geef ik nog wat tips over het gebruik +van AGE in het algemeen. + +- Bij het laden van plaatjes in BASIC kan een COLOR=RESTORE + ingegeven worden. Na dit commando zal het in AGE + ingestelde palet automatisch ingesteld worden. Zo zou het + er in BASIC uitzien: + + 10 SCREEN 5 + 20 BLOAD "PLAATJE.GE5",S + 30 COLOR = RESTORE + 40 IF INKEY$="" THEN 40 ELS END + +- Probeer nooit een niet *.DAT file inteladen met de DAT + file mode ingesteld, dit sloopt uw menu's door dat de + tekening dan over je menu's heen geladen wordt (dus in het + spritegeheugen!) Idem voor *.CMP files. + +- Wanneer u van plan bent om alleen AGE te gaan gebruiken, + kunt u het beste even een nieuwe batchfile aanmaken die + meteen AGE.COM start. Dit gaat als volgt: + + A>COPY CON AUTOEXEC.BAT [RETURN] + A>AGE [RETURN] + A>[CTRL] + [Z] [RETURN] + + Nu zal AGE direkt opstarten en niet steeds het intromenu! + + +## S P E N + + +Het kopje heeft eigenlijk geen zin omdat ik SPEN niet ga +bespreken. Wij hebben SPEN gebruikt voor Bozo's Big +Adventure maar behalve het 'SAVE'en en 'LOAD'en is ons niet +duidelijk hoe het programma werkt. Het is in ieder geval de +bedoeling met AGE sprites te ontwerpen, ze daarna in te +laden in SPEN, bij te werken en weg te saven. Met de +programma's DW2BAS.COM en DB2BAS.COM kunt u uw met SPEN +gemaakte DB of DW files, (deze files kunt u in een assembler +in laden en dan heeft u de complete sprite data!) omzetten +naar sprite-data's in BASIC. Met de SAMPLE*.* files kunt u +zien hoe het werkt. + + +## N A W O O R D + +Zo, dat zit erop, ik hoop dat ik met deze cursus het een en +ander over Dots Designer's Club (de originele titel!) +duidelijk heb gemaakt. Ik zou zeggen ga flink teken voor het +Magazine of de Special, misschien wel voor een eigen demo +voor de Picturedisk! Nou ja, dat zoekt u zelf ook maar uit! + +Bart Schouten + + +Nvdr. Als u wel meer over SPEN kunt vertellen, schrijf er +dan een tekst over en stuur die dan op een diskette naar de +Sunrise postbus. Uppen bij een van de twee Sunrise BBS'en is +ook goed. Bij voorbaat dank! \ No newline at end of file diff --git a/sunrise_special/2/geheugen_schakelen.md b/sunrise_special/2/geheugen_schakelen.md new file mode 100644 index 0000000..61be24b --- /dev/null +++ b/sunrise_special/2/geheugen_schakelen.md @@ -0,0 +1,480 @@ +# G E H E U G E N S C H A K E L E N + + +Een tijdje geleden vroeg iemand aan mij waarom de +replayroutine die bij FAC Soundtracker wordt geleverd niet +werkt als je hem gebruikt in een machinetaalprogramma dat +vanuit de bootsector opstart. + +Eerst wist ik het antwoord niet, maar toen ik de routine +eens bekeek zag ik al snel waar het aan lag: de FAC schakelt +het geheugen niet op de juiste manier! + +Waarom gaat het dan vanuit BASIC wel goed zult u denken. Om +dat uit te leggen, moet ik eerst uitleggen hoe het geheugen +geschakeld dient te worden. + + +## P R I M A I R E E N S U B S L O T E N + +Elke MSX computer heeft vier primaire sloten, die elk weer +kunnen worden gesplitst in vier subsloten. Zowel de primaire +als de subsloten worden genummerd van 0 tot 3. + +Een voorbeeld van een slotindeling is (FS-A1ST MSX turbo R): +``` + 0-0 0-2 3-0 3-1 3-2 3-3 + +0000 MAIN - RAM SUB - HIRO +3FFF ROM ROM + +4000 MAIN FM RAM KANJI DISK HIRO +7FFF ROM BASIC BASIC ROM + +8000 - - RAM KANJI - HIRO +BFFF BASIC + +C000 - - RAM - - - +FFFF +``` + +Slot 1 en 2 zijn de cartridge sloten, de indeling hiervan is +afhankelijk van wat men in het cartridgeslot stopt. Als er +een slotexpander in steekt, wordt het slot uitgebreid in +vier subsloten, bijvoorbeeld slot 1-0, 1-1, 1-2 en 1-3. + +Het MAIN ROM moet volgens de MSX standaard altijd in slot 0 +zitten, als slot 0 is geexpandeerd is dit dus slot 0-0. Het +MAIN ROM vanaf adres &H0000 bevat het BIOS (Basic Input +Output System), vanaf &H4000 staat de BASIC interpreter. + +Slot 0 is bij de turbo R geexpandeerd voor de FM BASIC, die +in slot 0-2 is geplaatst. In slot 3-0 zit het memory mapper +RAM, de I/O poorten &HFC t/m &HFF bepalen welke memory +mapper segmenten hier staan. De SUB ROM is de MSX2 BASIC, de +KANJI ROM is de MSX2+ en MSX turbo R BASIC. + +De diskROM zit op adres &H4000 in slot 3-2. Eigenlijk zijn +er bij de turbo R meerdere diskROMs, die met een +omschakeladres worden geselecteerd. Welke diskROM er is +geselecteerd is o.a. afhankelijk van de mode waarin de +computer werd opgestart (Disk BASIC 1.0 of Disk BASIC 2.01). + +In slot 3-3 bevindt zich tenslotte de ingebouwde +programmatuur, die ik hier voor het gemak Hiro noem. Dit is +het ingebouwde pakket, dat met een CALL HIRO of een reset +(met de keuzeschakelaar in de linker positie) is op te +roepen. + + +## S L O T I D + +De BIOS heeft een handige manier om een bepaald slot weer te +geven, dit is de zogenaamde slot ID byte. Deze byte is als +volgt opgebouwd: +``` +MSB 7 6 5 4 3 2 1 0 LSB + + E 0 0 0 --S-- --P-- +``` +E: slot geexpandeerd? (1=ja) +S: nummer van secundair slot +P: nummer van primair slot + +S wordt verwaarloosd als E=0. Enkele voorbeelden maken het +misschien duidelijker: + +Slot: ID-byte: + +2 &B00000010 &H02 +3-2 &B10001011 &H8B +3-3 &B10001111 &H8F +0 &B00000000 &H00 +0-0 &B10000000 &H80 + +Merk op dat er verschil is tussen slot 0 en 0-0!!! Dit is +natuurlijk alleen zo bij computers waarbij slot 0 is +geexpandeerd, maar als je een programma schrijft is het toch +meestal de bedoeling dat het op alle computers werkt denk +ik. + + +## B I O S R O U T I N E S + +De veiligste manier om met het geheugen te schakelen is +natuurlijk via het BIOS, zo hoort het ook via de standaard. +Het BIOS heeft de volgende routines voor slotschakeling e.d. +in huis: + +&H000C RDSLT + +Werking: Lees een byte uit een bepaald slot. Het slot + wordt geselecteerd, de byte wordt gelezen en de + oude slot schakeling wordt weer hersteld. De + interrupts worden uitgezet bij aanroep van deze + routine, en niet meer aangezet. +Input: A = slot ID byte + HL = adres +Output: A = data +Registers: AF, BC, DE + + +&H0014 WRSLT + +Werking: Schrijf een byte naar een bepaald slot. Het slot + wordt geselecteerd, de byte wordt geschreven en + de oude slot schakeling wordt weer hersteld. De + interrupts worden uitgezet bij aanroep van deze + routine, en niet meer aangezet. +Input: A = slot ID byte + HL = adres + E = data +Output: - +Registers: AF, BC, D + + +&H001C CALSLT + +Werking: Roept een routine in een bepaald slot aan (inter- + slot call). +Input: Bit 9-16 van IY = slot ID byte + IX = adres +Hangt verder af van de routine die wordt aangeroepen. Let op +dat hierbij de slot ID byte in de hoogste 8 bits van IY moet +staan (bij de R800 is dit IYL!). + + +&H0024 ENASLT + +Werking: Selecteer een slot zodat het kan worden gebruikt. + De interrupts worden bij het aanroepen van deze + routine uitgezet en niet meer aangezet. +Input: A = slot ID byte + H = bit 7 en 6 bepalen welke page +Output: - +Registers: allemaal +De waarde van de bits 6 en 7 van H bepalen welke page er +wordt geschakeld. Het komt er dus in feite op neer dat de +page wordt geschakeld naar de page waarin het adres voorkomt +dat in HL staat. + +Page 0 &H0000-&H3FFF H tussen &H00 en &H3F +Page 1 &H4000-&H7FFF H tussen &H40 en &H7F +Page 2 &H8000-&HBFFF H tussen &H80 en &HBF +Page 3 &HC000-&HFFFF H tussen &HC0 en &HFF + + +&H0030 CALLF + +Deze routine kan behalve met CALL &H0030 ook met RST &H30 +worden aangeroepen. Dit kost maar een byte in plaats van +drie, en is iets sneller. + +Werking: roept een routine in een bepaald slot aan (inter- + slot call) +Input en output zijn afhankelijk van de routine die wordt +aangeroepen. De waarde van AF wordt gewijzigd. De invoer van +adres en slot gaan als volgt: +``` + RST &H30 ; inter-slot call + DB SLOT ; slot ID byte van slot waarin + ; de routine staat + DW ADRES ; adres van aan te roepen routine +``` +Dit is dus een zeer snelle en korte methode om een routine +in een "ver" slot aan te roepen. Dit wordt veel gebruikt bij +hooks, daar is precies voldoende ruimte (5 bytes) om een RST +&H30 plus slot, adres en een RET neer te zetten. + +Voorbeeld: +``` + RST &H30 + DB &H83 + DW &H5A00 +``` +Hiermee wordt de routine op adres &H5A00 in slot 3-0 +aangeroepen. Dit was het overzicht van de BIOS routines voor +geheugen schakeling, nu gaan we verder met ons "probleem". + + +## R O M / R A M S C H A K E L E N + +Bij ML programma's die vanuit BASIC worden opgestart is het +vaak nodig om de MAIN ROM tijdelijk weg te schakelen en daar +RAM neer te zetten, bij programma's die vanuit MSX-DOS of de +bootsector opstarten is het vaak nodig om het RAM tijdelijk +weg te schakelen en daar RAM neer te zetten. Meestal moet de +oude situatie later weer worden hersteld. + +U kunt dit het beste doen met de routine ENASLT op adres +&H0024. Met H geeft u op welke page u wilt schakelen en in A +staat de slot ID byte. + +Waar haalt u nu de juiste slot ID byte vandaan? U zou +natuurlijk een routine kunnen schrijven die het RAM zoekt, +maar gelukkig heeft het besturingssysteem van de MSX +computer dit bij het opstarten al gedaan. Per page staat +er in het systeem RAM een slot ID byte die aangeeft in welk +slot het RAM voor die page staan. U kunt deze RAM ID bytes +vinden op de volgende adressen: + +Page 0 (&H0000-&H3FFF) Adres &HF341 +Page 1 (&H4000-&H7FFF) Adres &HF342 +Page 2 (&H8000-&HFFFF) Adres &HF343 +Page 3 (&HC000-&HFFFF) Adres &HF344 + +Normaal gesproken zijn deze slot ID bytes aan elkaar gelijk, +maar voor de zekerheid is het natuurlijk beter om altijd het +juiste adres te gebruiken. De computer zoekt overigens naar +de grootste mapper, die wordt bij het opstarten +geselecteerd. + +Met deze gegevens komen we tot de volgende standaard +routines. + +## R A M A A N + +Met deze routine selecteert u ROM op &H0000 (page 0): +``` + LD A,(&HF341) + LD H,&H00 + CALL &H24 +``` +Met deze routine selecteert u RAM op &H4000 (page 1): +``` + LD A,(&HF342) + LD H,&H40 + CALL &H24 +``` +Gebruik altijd deze methode, dan werkt het altijd. Bij het +wegschakelen van de BIOS op page 0 moet u er wel voor zorgen +dat de interrupts uit staan, of dat op adres &H0038 uw eigen +interrupt routine staat. Anders slaat de computer vrijwel +zeker vast zodra er een interrupt optreedt. + +Het wegschakelen van de MAIN ROM op page 1 (hier staat de +BASIC interpreter) zal in een ML programma meestal geen +problemen geven, er zullen zelden routines uit de BASIC +interpreter worden gebruikt. Vergeet niet het MAIN ROM weer +terug te schakelen voordat u weer naar BASIC terugkeert, +anders slaat de computer natuurlijk vast. + +Wilt u toch de routines in de BASIC interpreter gebruiken, +dan kunt u daarvoor de BIOS routine CALBAS gebruiken. Deze +routine staat op adres &H159, het adres van de routine die u +wilt aanroepen moet in IX staan. + + +## R O M A A N + +En nu zijn we dan tot de kern van de zaak doorgedrongen: wat +is de juiste manier om ROM te selecteren op page 0 en/of +page 1. + +Omdat de MAIN ROM zich in een MSX computer altijd in slot +0-0 of slot 0 bevindt, is er eigenlijk geen adres in het +systeem RAM dat u kunt uitlezen om de slot ID byte van het +MAIN ROM te vinden. + +Toch kunt u hem wel uit het MAIN ROM halen. Op adres &HFCC1 +staat namelijk een tabel van 4 bytes, die per primair slot +aangeeft of het slot is geexpandeerd of niet. Slot 0 staat +op &HFCC1, slot 1 op &HFCC2, enz. + +Deze tabel heet EXPTBL (EXPansion TaBLe). Er zijn slechts +twee waarden mogelijk: &H80 (wel geexpandeerd) en &H00 (niet +geexpandeerd). Het leuke is nu dat deze byte voor slot 0 +precies het slot van de MAIN ROM aangeeft! + +Is slot 0 namelijk geexpandeerd, dan staat er op adres +&HFCC1 een &H80, de slot ID byte van slot 0-0. Is slot 0 +niet geexpandeerd, dan staat er op adres &HFCC1 een &H00, de +slot ID byte voor slot 0! + +De juiste routines om ROM te selecteren zijn dus: + +ROM selecteren op &H0000 (page 0): +``` + LD A,(&HFCC1) + LD H,&H00 + CALL &H24 +``` +ROM selecteren op &H4000 (page 1): +``` + LD A,(&HFCC1) + LD H,&H40 + CALL &H24 +``` +Gebruik altijd deze methode, dan werkt het altijd! Helaas +zijn er veel programmeurs die het niet zo doen, hierover +gaat de volgende paragraaf. + + +## H O E H E T N I E T M O E T + +Een aantal (Nederlandse) programmeurs denken dat op adres +&HFCC0 de slot ID byte staat voor het MAIN ROM in page 0 en +op adres &HFCC1 de slot ID byte voor het MAIN ROM in page 1. +Dit is klinkklare onzin!!! Op adres &HFCC1 staat de slot ID +byte voor page 1 EN page 0!!! + +Helaas zijn er daarom veel programmeurs die als volgt ROM op +&H0000 selecteren: +``` + LD A,(&HFCC0) + LD H,&H00 + CALL &H24 +``` +Dit is dus echt helemaal fout!!! Doe dit dus nooit zo!!! Ik +snap wel hoe ze hierbij komen, het komt door CALSLT. Deze +BIOS routine wordt vaak onder MSX-DOS gebruikt om een BIOS +routine aan te roepen. Voor CALSLT moet de slot ID byte in +de HOOGSTE ACHT BITS van register IY staan. Dit kan als +volgt worden gedaan: +``` + LD IY,(&HFCC0) +``` +Op deze manier worden de laagste acht bits geladen met de +waarde op &HFCC0 (die waarde doet er verder niet toe), en de +hoogste acht bits (waar het om draait) met de waarde op +&HFCC1, precies zoals de bedoeling is. Hier komt misschien +de verwarring met &HFCC0 vandaan. + + +## B S A V E + +Dat het echt onzin is om &HFCC0 te gebruiken om de slot ID +byte van het MAIN ROM te achterhalen blijkt wel als we gaan +kijken wat er nu eigenlijk wel op &HFCC0 staat. Op adres +&HFCBF staat een 2 bytes waarde die SAVENT heet. Dit is een +beetje vreemde naam, want dit adres is het startadres bij +BSAVE en BLOAD: + +BSAVE"NAAM.BIN",beginadres,eindadres,startadres + +Dit adres staat dus op &HFCBF en &HFCC0, &HFCC0 bevat dus de +high byte van het BSAVE start adres!!! Misschien helpt een +voorbeeldje hier: + +BLOAD"NAAM.BIN",R + +is precies hetzelfde als + +BLOAD"NAAM.BIN" +DEFUSR=PEEK(&HFCBF)+256*PEEK(&HFCC0) +U=USR(0) + +U begrijpt dus wel dat elke programmeur die &HFCC0 gebruikt +om de slot ID byte te achterhalen niet helemaal goed bij +zijn hoofd is, want de waarde die daar staat is volkomen +onvoorspelbaar!!! + + +## H O E H E T O O K N I E T M O E T + +Een andere methode die ik vaak zie is de volgende, het maakt +hierbij niet uit of het om page 0 of page 1 gaat: +``` + XOR A + LD H,&H40 ; &H00 voor page 0 + CALL &H24 +``` +Zoals u weet is XOR A hetzelfde als LD A,0, voor de slot ID +byte wordt dus 0 genomen. Bij computers waar slot 0 niet +geexpandeerd is geeft dit natuurlijk geen problemen, maar +als slot 0 wel geexpandeerd kan dit problemen geven. + +Dit komt omdat de routine op &H24 naar bit 7 kijkt om te +kijken of het secundaire slot moet worden veranderd of niet. + +Stel u heeft een computer waarvan slot 0 is geexpandeerd +(bijvoorbeeld een turbo R), en u heeft slot 3-3 geselecteerd +op &H4000 (page 1). Nu doet u +``` + XOR A + LD H,&H40 + CALL &H24 +``` +om het ROM te selecteren op &H4000. Dit gaat nu mis! De +routine op &H24 kijkt immers naar bit 7, en die is gelijk +aan 0. Het gevolg is dat slot 0-3 wordt geselecteerd, dit +uiteraard met onbekende gevolgen (meestal een vastloper). + + +## H E T F S T P R O B L E E M + +U raadt het al: de replay routine van FAC Soundtracker doet +het niet altijd goed omdat hij het geheugen verkeerd +schakelt. Om precies te zijn schakelt FAC Soundtracker op de +volgende manier ROM op &H0000: +``` + LD A,(&HFCC0) + LD H,&H40 + CALL &H24 +``` +Zoals u weet bevat &HFCC0 de high-byte van het BSAVE +startadres, de waarde op dit adres is dus onvoorspelbaar. Er +wordt op deze manier dus naar een willekeurig slot +geschakeld, met onbekende gevolgen. + + +## W A A R O M W E R K T H E T M E E S T A L W E L ? + +De oplettende lezertjes vragen zich nu natuurlijk af waarom +FST.BIN onder BASIC wel altijd werkt. Dit wordt veroorzaakt +door toeval, oftewel ontzettende mazzel voor de FAC. + +Zoals u weet staat de MAIN ROM altijd in slot 0 of 0-0, +waarvan de slot ID bytes resp. &H00 en &H80 zijn. &H80 is +echter altijd goed, want als slot 0 niet geexpandeerd is +maakt het tenslotte niet uit of het subslot wordt veranderd +of niet. + +Blijkbaar staat er dus bij gebruik van FST.BIN vanuit BASIC +altijd &H80 op adres &HFCC0, anders zou de routine dus niet +op alle computers werken! Hoe komt die &H80 daar? + +Zoals u weet zijn zowel de drumkits als de muziekjes van FAC +Soundtracker binaire files van 16 kB. Dit zijn files van het +volgende type: + +BSAVE"FILENAAM.EXT",&H8000,&HBFFF,&H8000 + +Het startadres is dus &H8000, de high byte daarvan &H80. +Door het BLOADen van Soundtracker muziekjes of drumkits +wordt dus automatisch de waarde &H80 op adres &HFCC0 gezet +(en de waarde &H00 op &HFCBF, maar dat doet er hier niet +toe). En dat is nu precies de waarde die altijd werkt als +slot ID byte voor het MAIN ROM!!! Kortom, de FAC heeft +ontzettende mazzel gehad. + + +## D E M O R A A L + +Ik hoop dat alle Nederlandse programmeurs hier wat van +hebben geleerd, en voortaan de enige echte standaard +routines gebruiken om het geheugen te schakelen. Ik zal ze +hier voor de zekerheid nog maar een keer geven: +``` +RAM000: LD A,(&HF341) + LD H,&H00 + CALL &H24 + +RAM400: LD A,(&HF342) + LD H,&H40 + CALL &H24 + +ROM000: LD A,(&HFCC1) + LD H,&H00 + CALL &H24 + +ROM400: LD A,(&HFCC1) + LD H,&H40 + CALL &H24 +``` +De FAC is echt niet de enige die dit fout doet, er zijn +helaas veel meer Nederlandse MSX programmeurs die dit +verkeerd doen. Ik hoop dat dit artikel daar verandering in +gaat brengen... + +Stefan Boer diff --git a/sunrise_special/2/interrupt_service_routines.md b/sunrise_special/2/interrupt_service_routines.md new file mode 100644 index 0000000..c9c4eb3 --- /dev/null +++ b/sunrise_special/2/interrupt_service_routines.md @@ -0,0 +1,801 @@ +# I N T E R R U P T S E R V I C E R O U T I N E S + + +Soms zit het mee en soms zit het tegen. Deze eerste regels +zijn als laatste aan het artikel toegevoegd omdat ik tot de +ontdekking ben gekomen dat een dergelijk artikel al op MCM +nummer 51 heeft gestaan. Ik ben zelf geen lid van MCM en zie +het blad vrij weinig. Ik heb de informatie nota bene van +Sunrise Magazine #1 af moeten halen waar een beschrijving +van MCM 51 op staat. Het is nooit de bedoeling van Sunrise +geweest om oud nieuws te gaan vertellen, maar ik wist gewoon +niet dat MCM al iets dergelijks gedaan heeft. Affijn, ik +weet niet precies wat er allemaal in dat artikel staat, maar +ik hoop dat ik wat informatie toe kan voegen zodat dit niet +een nutteloos artikel is. + +(Nvdr. Maak je maar niet ongerust, Alex. Jouw artikel is +veel beter en uitgebreider dan dat in MCM.) + + +## H E T M A K E N V A N E E N I S R + + +ISR is een algemeen gebruikte afkorting voor Interrupt +Service Routine, oftewel een routine die wordt aangeroepen +als er een interrupt optreedt. Interrupts bestaan al lang +als we het over de computerhistorie hebben, want ze zijn al +terug te vinden in de eerste commercieel verkochte +computers. Dat is ook niet zo gek als je bedenkt dat +interrupts heel handig kunnen zijn. De populariteit van +interrupts is bijna grenzeloos en er is tegenwoordig geen +processor meer in de handel die geen interrupt faciliteiten +biedt. Natuurlijk zijn er altijd situaties waarbij +interrupts alleen maar aan de complexiteit bijdragen, maar +omdat wij allen maar een simpele MSX bezitten komt die +situatie bij ons nauwelijks voor. + + +## I N T E R R U P T S V S P O L L I N G + +Polling is de tegenhanger van interrupts. Bij polling wordt +er geen interrupt gegenereerd, maar zal de CPU zelf +periodiek naar een randapparaat kijken of deze iets aan te +bieden heeft (om maar iets te noemen). Nu zal je misschien +denken dat polling de computer erg traag maakt, maar dat is +helemaal niet waar. Polling wordt nl. o.a. gebruikt bij +dingen waarvan je in zekere mate kunt voorspellen dat de CPU +er aandacht aan moet besteden zoals bij een screensplit. + +We kunnen dus rustig stellen dat polling zo gek nog niet is +en dat wordt nog een bevestigd door het feit dat de +reaktietijd van polling wel 10x zo hoog kan zijn als de +reaktietijd van een interrupt. Dit komt omdat de ISR eerst +de oude waarde van alle registers moet bewaren om daarna de +bron van de interrupt te achterhalen. Pas na deze testen kan +naar de routine gesprongen worden die de feitelijke aktie +moet uitvoeren. + +Met polling heb je dit alles niet, omdat de registers niet +bewaard hoeven te worden en je meteen na de test weet waar +de interrupt vandaan komt. Vooral bij tijdkritische signalen +is polling dus beter dan interrupts omdat je veel sneller +kunt reageren op een signaal. Natuurlijk blijft het bij +polling wel belangerijk dat je ongeveer weet wanneer er +getest moet worden omdat de reaktietijd ook heel laag kan +zijn indien je niet konstant aan het pollen bent maar ook +andere dingen doet. + +Het laatste voordeel van polling boven interrupts is het +feit dat je precies weet waar het lopende programma +onderbroken wordt als de polling positief blijkt. Met +interrupts moet je altijd nog oppassen bij bv. het +beschrijven van de VDP omdat daar geen interrupt tussendoor +mag komen. Met polling heb je dit probleem niet omdat je +immers weet waar het optreed. + + +## W A N N E E R I N T E R R U P T S ? ? + +ALs we het even over een algemene moderne computer hebben +kunnen we stellen dat interrupts voor twee hoofdsituaties +gebruikt worden en wel: +- bij het verwerken van binnenkomende data 'bursts'. +- bij het snel moeten kunnen reageren op een binnenkomend + tijdkritisch signaal. + +Een burst is een situatie waarin in korte tijd een grote +hoeveelheid data binnen kan komen. Een disk-controller +levert bv. complete clusters aan de CPU die dat dan maar +snel mag verwerken omdat het volgende blok er weer aan kan +komen (bij MSX zit dit echter niet op een interrupt, dat is +ook de reden waarom je geen muziek af kunt spelen tijdens +het laden). + +Het is maar moeilijk te voorspellen wanneer de data binnen +komt en daarom zijn interrupts eigenlijk verplicht bij deze +situatie omdat je anders in een polling lus moet gaan zitten +om toch snel te kunnen reageren en niet de kans te lopen een +complete cluster aan data mis te lopen. Op MSX moet het dus +met zo'n lus en men is daarin zelfs zo ver gaan om de +interrupts tijdens het lezen van disk stil te leggen omdat +de CPU anders wel eens tijd tekort kan komen. Polling is +hier dus niet de beste oplossing omdat die methode feitelijk +90% van de tijd test op iets dat er (nog) niet is. + +Bij een screensplit is dat echter een heel ander verhaal. +Daar is elke microseconde winst een grote vooruitgang omdat +je de beeldopbouw nu eenmaal niet even stil kunt leggen. +Screensplits zijn ook heel voorspelbaar omdat ze immers op +een vast tijdsinterval optreden en daarom is polling hier +een betere oplossing (ook vanwege de reaktiesnelheid). + +Kijk maar eens naar de bovenste screensplit van uw geliefde +magazine. U zult hier twee zwarte lijnen zien die o.a. het +gevolg zijn van de relatief trage reaktie van de interrupt. +Ik zal in de toekomst eens proberen om die screensplit te +vervangen door polling om op die manier ��n van de twee +lijnen weg te halen (je zult het dus vanzelf wel merken). + +Ik heb eigenlijk niet een uitgesproken mening over de manier +om een screensplit te detecteren omdat het praktisch blijkt +dat het niet zo gek veel uit maakt of je nu polling of +interrupts gebruikt om een screensplit mee af te handelen. +De regel dat je interrupts kunt gebruiken om tijdkritische +signalen op te vangen werkt met polling net zo goed. Je moet +er bij polling echter wel even op letten waar je de tests +uitvoert en dat is bij interrupts niet zo. Daar hoef je er +alleen maar voor te zorgen dat de interrupts zoveel mogelijk +aan staan. + + +## I S R M O G E L I J K H E D E N O P M S X + +Laten we maar eens wat methoden en programmaatjes bekijken +die interrupts afhandelen en polling uitvoeren. Om te +beginnen zullen we de interrupts behandelen. + +Om een interrupt goed te kunnen begrijpen zullen we toch met +de hardware moeten beginnen omdat de in overvloed aanwezige +zwarte klodders immers interrupts genereren. Daarom volgt nu +een standaard protocol waar ALLE interrupts mee werken: + +- Het randapparaat (een chip) genereert een interrupt en zet + deze op de INT lijn. + +- Op een gegeven moment honoreert de CPU deze interrupt en + gaat afhankelijk van de processor en de instelling van + deze processor naar een ISR. + +- Hier worden meestal eerst enkele registers op de stack + gezet. Op sommige processoren gebeurt dit zelfs + hardwarematig (zoals de IRQ lijn op een MC6809). Nu wordt + meestal eerst de bron van de interrupt gewist, omdat de + INT lijn van dat apparaat nog steeds aktief is. Wordt dit + niet gedaan dan zal na afronding van de ISR meteen weer + een interrupt optreden die naar dezelfde ISR springt. Dit + weghalen van de oorzaak van een interrupt wordt nog wel + eens vergeten waardoor het net lijkt of je programma vast + loopt terwijl het feitelijk gewoon eeuwig in de ISR blijft + hangen. + +- Nu wordt de feitelijke interrupt aktie uitgevoerd en nadat + alle registers weer van de stack gehaald zijn zal het + programma dat liep voor de interrupt hervat worden. + +Dan volgt nu een lijst van dingen die gebeuren als op een +MSX een interrupt optreed op de INT-lijn. + +- De CPU accepteert altijd de interrupt maar hoeft hem miet + noodzakelijk onmiddelijk te honoreren (dit is het geval + als een DI instruktie gedaan is). Als de CPU de interrupt + uiteindelijk toch honoreerd zal naar adres 38H gesprongen + worden. Hier staat normaal gesproken een ROM met op adres + 38H een sprong naar de eigenlijke ISR + +- In de ISR aangekomen worden eerst alle registers op de + stack gezet (ook schaduwregisters). Nu wordt naar adres + FD9AH gesprongen. Zodra dit gedaan is wordt gekeken of de + interrupt van het 50/60Hz signaal van de VDP afkomstig is + en wordt naar FD9FH gesprongen indien dit zo is. + +- Nu wordt het toetsenbord afgetast en ook worden alle + vuurknoppen gelezen en bewaard. Bij een MSX2+ en de turbo + R wordt ook naar de PAUZE toets gekeken wordt en wel + nadat naar FD9AH gesprongen is. + + +Wat nu volgt is een listing van het voor ons belangrijke +deel van de MSX2 ISR. Nogmaals, de ISR's van de 2+ en de +turbo R zijn een beetje anders (dat verklaart voor een deel +waarom screensplits op de turbo R vaak fout gaan indien deze +voor MSX2 geschreven zijn). +``` +&H0038 C33C0C JP &H0C3C + +&H0C3C E5 PUSH HL ; Push registers +&H0C3D D5 PUSH DE +&H0C3E C5 PUSH BC +&H0C3F F5 PUSH AF +&H0C40 D9 EXX +&H0C41 08 EX AF,AF +&H0C42 E5 PUSH HL ; Push schaduwregisters +&H0C43 D5 PUSH DE +&H0C44 C5 PUSH BC +&H0C45 F5 PUSH AF +&H0C46 FDE5 PUSH IY ; Push indirektie reg. +&H0C48 DDE5 PUSH IX +&H0C4A CD9AFD CALL &HFD9A ; Algemene INT.hook +&H0C4D CD7914 CALL &H1479 ; 50/60Hz VDP int. ? +&H0C50 F2020D JP P,&H0D02 ; Nee +&H0C53 CD9FFD CALL &HFD9F ; 50/60Hz timing hook +&H0C56 FB EI ; Zie: Opm. 1 +&H0C57 32E7F3 LD (&HF3E7),A ; Bewaar S#0 voor BASIC +&H0C5A E620 AND &H20 ; Spritebotsing ? +&H0C5C 216DFC LD HL,&HFC6D ; Zie: Opm. 2 +&H0C5F C4F10E CALL NZ,&H0EF1 +&H0C62 2AA2FC LD HL,(&HFCA2); Voor: ON INTERVAL= +&H0C65 2B DEC HL +&H0C66 7C LD A,H +&H0C67 B5 OR L +&H0C68 2009 JR NZ,&H0C73 +&H0C6A 217FFC LD HL,&HFC7F +&H0C6D CDF10E CALL &H0EF1 ; Zie: Opm. 2 +&H0C70 2AA0FC LD HL,(&HFCA0) +&H0C73 22A2FC LD (&HFCA2),HL; Herstart ON INTERVAL= +&H0C76 2A9EFC LD HL,(&HFC9E) +&H0C79 23 INC HL +&H0C7A 229EFC LD (&HFC9E),HL; Softwareklok verhogen +&H0C7D 3A3FFB LD A,(&HFB3F) ; Doe PSG PLAY statement +&H0C80 4F LD C,A +&H0C81 AF XOR A +&H0C82 CB19 RR C +&H0C84 F5 PUSH AF +&H0C85 C5 PUSH BC +&H0C86 DC3111 CALL C,&H1131 +&H0C89 C1 POP BC +&H0C8A F1 POP AF +&H0C8B 3C INC A +&H0C8C FE03 CP &H03 +&H0C8E 38F2 JR C,&H0C82 ; Doe volgende PSG stem +&H0C90 21F6F3 LD HL,&HF3F6 ; Zie: Opm. 3 +&H0C93 35 DEC (HL) +&H0C94 206C JR NZ,&H0D02 ; Einde ISR +&H0C96 3601 LD (HL),&H01 +&H0C98 AF XOR A +&H0C99 CD0212 CALL &H1202 ; Lees ALLE vuurknoppen +&H0C9C E630 AND &H30 +&H0C9E F5 PUSH AF +&H0C9F 3E01 LD A,&H01 +&H0CA1 CD0212 CALL &H1202 ; idem. +&H0CA4 E630 AND &H30 +&H0CA6 07 RLCA +&H0CA7 07 RLCA +&H0CA8 C1 POP BC +&H0CA9 B0 OR B +&H0CAA F5 PUSH AF +&H0CAB CD1C12 CALL &H121C ; idem. +&H0CAE E601 AND &H01 +&H0CB0 C1 POP BC +&H0CB1 B0 OR B +&H0CB2 4F LD C,A +&H0CB3 21E8F3 LD HL,&HF3E8 ; Bewaaradres vuurknoppen +&H0CB6 AE XOR (HL) +&H0CB7 A6 AND (HL) +&H0CB8 71 LD (HL),C +&H0CB9 4F LD C,A +&H0CBA 0F RRCA +&H0CBB 2170FC LD HL,&HFC70 ; Spatiebalk bewaaradres +&H0CBE DCF10E CALL C,&H0EF1 +&H0CC1 CB11 RL C +&H0CC3 217CFC LD HL,&HFC7C ; Joy 2 knop 2 +&H0CC6 DCF10E CALL C,&H0EF1 +&H0CC9 CB11 RL C +&H0CCB 2176FC LD HL,&HFC76 ; Joy 2 knop 1 +&H0CCE DCF10E CALL C,&H0EF1 +&H0CD1 CB11 RL C +&H0CD3 2179FC LD HL,&HFC79 ; Joy 1 knop 2 +&H0CD6 DCF10E CALL C,&H0EF1 +&H0CD9 CB11 RL C +&H0CDB 2173FC LD HL,&HFC73 ; Joy 1 knop 1 +&H0CDE DCF10E CALL C,&H0EF1 +&H0CE1 AF XOR A +&H0CE2 32D9FB LD (&HFBD9),A ; Zie: Opm. 4 +&H0CE5 CD120D CALL &H0D12 +&H0CE8 2018 JR NZ,&H0D02 +&H0CEA 21F7F3 LD HL,&HF3F7 ; Zie: Opm. 5 +&H0CED 35 DEC (HL) +&H0CEE 2012 JR NZ,&H0D02 +&H0CF0 3602 LD (HL),&H02 +&H0CF2 21DAFB LD HL,&HFBDA +&H0CF5 11DBFB LD DE,&HFBDB +&H0CF8 010A00 LD BC,&H0A +&H0CFB 36FF LD (HL),&HFF ; Oude toestand toetsbrd. +&H0CFD EDB0 LDIR ; matrix wissen +&H0CFF CD4E0D CALL &H0D4E +&H0D02 DDE1 POP IX +&H0D04 FDE1 POP IY +&H0D06 F1 POP AF +&H0D07 C1 POP BC +&H0D08 D1 POP DE +&H0D09 E1 POP HL +&H0D0A 08 EX AF,AF +&H0D0B D9 EXX +&H0D0C F1 POP AF +&H0D0D C1 POP BC +&H0D0E D1 POP DE +&H0D0F E1 POP HL +&H0D10 FB EI +&H0D11 C9 RET + +&H0EF1 7E LD A,(HL) +&H0EF2 E601 AND &H01 +&H0EF4 C8 RET Z + . (Voor ons onbelangrijke code) + . + . + +&H1479 DBBA IN A,(&HBA) ; Lichtpen poort +&H147B E610 AND &H10 +&H147D 200D JR NZ,&H148C +&H147F 21FFFA LD HL,&HFAFF ; (Lightpen int request) +&H1482 CBFE SET 7,(HL) +&H1484 3E20 LD A,&H20 +&H1486 D3BB OUT (&HBB),A ; Ook lichtpen +&H1488 F608 OR &H08 +&H148A D3BB OUT (&HBB),A +&H148C DB99 IN A,(&H99) ; Lees statreg. 0 van VDP +&H148E A7 AND A ; Zie ook: Opm 5 +&H148F C9 RET +``` + +Opm. 1 +Nadat naar &HFD9F is gesprongen worden de interrupts weer +aangezet en dit doet men om snel op bv. een nog komende +screensplit te kunnen reageren. Deze screensplit wordt dan +dus afgehandeld terwijl de vorige int ook nog 'bezig' is. +Meestal zal dit goed gaan, maar als het fout gaat dan is het +een lastig te vinden fout omdat hij alles behalve voor de +hand ligt. Ik raad het vroegtijdig aanzetten van interrupts +af omdat het een extra onzekere faktor aan programma's +toevoegt. + +Indien blijkt dat de afhandeling van een interrupt te lang +duurt moet je in de ISR gewoon een byte 'hoog' zetten zodat +een aparte routine buiten de ISR zich hier op kan timen. Dit +heeft als gevolg dat je een hele snelle ISR krijgt terwijl +de responstijd wel iets lager wordt. De methode is dus +alleen bruikbaar bij routines die geen extreem snelle +responstijd nodig hebben zoals een muziek replay routine +(alhoewel je wel een volkomen leek moet zijn om een +replayroutine zo traag te maken dat hij niet op de interrupt +kan!!). + +Indien er een interrupt optreedt als de INT lijn nog steeds +aktief is (oftewel als de bron van de interrupt nog niet +weggehaald is) zal een andere eventueel optredene interrupt +van dezelfde bron (bv. de VDP) verloren gaan en nooit +afgehandeld worden. Dit is gewoon een hardwareprobleem en +kan verder niet opgelost worden. Het is dus handig om liefst +snel na het optreden van een interrupt de bron te 'wissen'. + +Iets wat veel mensen vergeten te doen is het bewaren van +register A tijdens de &HFD9F hook omdat die na deze CALL nog +bewaard wordt en de verdere afhandeling van een sprite +botsing hangt ook nog van deze waarde af. Het is echter wel +handig dat je A zelf moet bewaren omdat je de ISR zo een +beetje kunt manipuleren. Als laatste instruktie voor de RET +van &HFD9F zou je A op een voor jou gunstige waarde kunnen +zetten. Ikzelf heb echter nog nooit een zinvolle invulling +aan deze mogelijkheid kunnen geven. + + +Opm. 2 +In het systeem RAM van de BIOS staat een tabel, TRPTBL +geheten met daarin een aantal plaatsen om alle mogelijke +BASIC interrupts in kwijt te kunnen. Zo heeft elke +funktietoets hier een byte in en ook de stop toets, een byte +voor de spritebotsing, de spatiebalk en alle joystick +vuurknoppen. Als laatste staat hier een byte voor de +INTERVAL instruktie in. Buiten BASIC wordt hier echter +weinig gebruik van gemaakt, dus ik zal er verder geen +woorden aan vuil maken. + + +Opm. 3 +Deze instrukiereeks zorgt er voor dat om de twee VDP +interrupts zowel het toetsenbord als alle vuurknoppen +gescanned worden. De preciese werking van dit blok code is +niet belangerijk omdat deze code toch alleen maar data +aanmaakt voor de eenvoudig te gebruiken BIOS calls. + + +Opm. 4 +Om te voorkomen dat bij het printen van een ASCII dubbelcode +twee toetsenbordklikken gegenereerd worden is dit byte +ingevoerd. Ik vind dit een behoorlijk klungelig iets om in +een ISR te zetten, maar de Microsoft jongens wisten zeker +niets beters. + + +Opm. 5 +Dit is het mechanisme dat de toetsenbord toetsherhaling +bijhoudt. Als dit er niet in had gezeten dan hadden we nu +allemaal heel houterig op ons toestenbord moeten drukken +omdat je anders om de haverklap een dubbel 'e' aan zou slaan +om maar een voorbeeld te geven. Deze routine zorgt er voor +dat nadat ��n toets ingedrukt is het even duurt voordat de +herhaling begint. + + +## D I T K A N B E T E R O F N I E T S O M S + +Natuurlijk kunnen wij zo'n ISR veel beter schrijven dan die +oenen van Microsoft (geen wonder dat IBM met Apple samen is +gaan werken). De MSX ISR is allemaal wel heel leuk en +aardig, maar de routine bevat eigenlijk geen nuttige dingen +voor de gemiddelde machinetaal programmeur. De ISR is dan +feitelijk ook geschreven om BASIC wat meer mogelijkheden te +geven maar daar hebben wij weinig aan. De routine is niet +alleen onhandig voor ons, maar ook nog eens onnodig traag +(we gebruiken immers bijna niets van de informatie die de +ISR aanmaakt). Wat we dus nodig hebben is een manier om al +die zinloze ellende over te slaan en daar bestaat een +buitengewoon leuk geintje voor. + + +## D E I N T E R R U P T B Y P A S S + +Wat we gaan doen is ervoor zorgen dat de interrupt alleen +nog maar naar &HFD9A springt en de rest overslaat. Ik zal nu +even een voorbeeld geven hoe je zoiets aanpakt. +``` +V_BLNK: EQU &HFD9F + + ORG &HFD9A ; Ints staan uit !!!!!!!! + JP VDPISR + +; De ISR waar alle interrupts naar toe springen +VDPISR: IN A,(&H99) ; Lees S#0 en wis bron van int. + PUSH AF + CALL LNEISR ; = Wat eerst op &HFD9A stond + POP AF + RLCA ; Bit 7 in Cy + CALL C,V_BLNK ; &HFD9F hook aanroepen (=VDP int.) + POP AF ; Haal terugkeeradres van stack + POP IX + POP IY + POP AF + POP BC + POP DE + POP HL + EX AF,AF + EXX + POP AF + POP BC + POP DE + POP HL + EI + RET +``` +V_BLNK is een afkorting voor Vertical Blank en het is een +standaars benaming (op zo'n beetje ALLE computers behalve +MSX) voor de standaard 50 of 60Hz interrupt die de computer +genereert. + +Het leuke van deze routine is dat je feitelijk een beetje +met de stack gaat knoeien om de routine naar je eigen hand +te zetten. De POP AF die na de &HFD9F call staat haalt het +terugkeeradres van de stack dat er door de CALL &HFD9A van +de ISR op is gezet. Nu hoef je alleen nog maar de gePUSHte +registers weer van de stack af te halen om de stack weer zo +te maken als hij was voordat de interrupt optrad. De RET +waar de routine mee eindigt springt terug naar de routine +waar de computer mee bezig was voordat de interrupt optrad. + +Op deze manier sla je dus zo'n beetje alles van de standaard +ISR over en heb de feitelijk het hele besturingssysteem plat +gelegt. Het voordeel van deze methode is dat je nog steeds +de beschikking hebt over de BIOS en dat je (op een aantal +na) nog steeds van deze funkties gebruik kunt maken. Dingen +als de toetsenbordaftasting werken echter niet meer, dus als +je nu iets van toetsenbord wilt lezen dan zal je de matrix +moeten scannen met bv. BIOS call &H0141. + +Een ander voordeel van deze methode is het feit dat de PAUZE +toets niet meer uitgelezen wordt op een MSX2+ en een turbo R +computer. De PAUZE toets wordt dus gewoon uitgeschakeld en +dat is bijzonder prettig. + +(Nvdr. Alleen softwarematige pauzetoetsen, zoals bij de +turbo R, kunnen op deze manier worden uitgeschakeld. De Sony +MSX2+ computers hebben een hardwarematige PAUZE toets, en +die is op deze manier natuurlijk niet te omzeilen.) + +Deze routine simuleert feitelijk de standaard ISR omdat bij +elke interrupt naar LNEISR gesprongen zal en ook naar V_BLNK +indien het een VDP int. is. Dit is echter niet zo'n handig +systeem. Je kunt beter naar LENISR springen als het geen VDP +int. is en anders naar V_BLNK Je springt dan dus niet meer +naar beide als het een VDP int. is. Op deze manier is de +reaktiesnelheid op een VDP int. hoger als bij de gegeven +routine staat. + +Het ziet er dan ongeveer zo uit: +``` +DOINT: IN A,(&H99) + RLCA + PUSH AF + CALL C,V_BLNK ; VDP int eerst voor snelle reaktie + POP AF + CALL NC,LNEISR ; Alleen bij screensplit + POP AF + POP IX + . + . + etc. +``` +Overigens kan alleen de VDP interrupts doorgeven aan de +processor via de CPU interrupt pin. Geen enkel ander IC kan +een interrupt aan de CPU doorgeven (als dit niet waar is, +dan hoor ik dat nog wel) ook al heeft dat IC daar wel +capaciteiten voor (zoals de klokchip dat een alarm kent). + +Voordat ik verder ga met het schrijven van een kompleet +eigen ISR wil ik toch eerst even wat kwijt over de andere +interrupts en de interrupt faciliteiten van de Z80, maar dat +kan je allemaal op de volgende submenu-optie lezen. + +## M O D E S + +De Z80 kent 3 verschillende 'modes' van interruptafhandeling +Deze modes kunnen met een simpele instruktie aangezet +worden. Ze heten: + +IM 0 <= Op MSX niet gedefinieerd!! +IM 1 <= Op MSX gebruikt +IM 2 <= Op MSX niet gedefinieerd!! + +Mode 0 kan alleen worden gebruikt als de interruptbron via +een I/O-module met de Z80 verbonden is. Bij een int. in mode +0 moet de I/O-module nl. ��n van de 8 ReSTart instrukties op +de databus zetten waarna de CPU automatisch naar dat adres +zal springen. Je kunt op deze manier dus 8 snelle ISR's +maken zodat de CPU niet hoeft te testen waar de int. vandaan +komt omdat de bron dat zelf al verteld heeft. Het nadeel van +deze methode is dat er een extra stuk hardware nodig is om +alles te kunnen realiseren (de I/O-module). Ik meen te weten +dat het op MSX wel werkt, maar het is absoluut niet +gedefinieerd en het kan dus in principe op elk nieuw type +MSX fout gaan. Dit geldt ook voor IM 2! + +Mode 1 is de mode die op MSX gebruikt wordt en daar hebben +we het straks weer over. + +Mode 2 heeft hetzelfde probleem als mode 0 want ook hier +moet er een I/O-module aanwezig zijn. Deze module levert +echter een 'vektor' aan de CPU en geen adres. Deze vektor is +8 bits groot en is het LOWBYTE van een 16 bits adres waarvan +het HIGHBYTE in het I-register staat. Dit register en de +vektor vormen samen een adrespointer. Op dit adres moet dan +feitelijk het adres staan waar de computer heen moet +springen. Op deze manier is het mogelijk om 128 +verschillende ISR's te maken (bit 0 van het gegenereerde +getal is nl. 0) zodat zonder ook maar 1 test te doen over +waar de interrupt vandaan komt naar de juiste routine wordt +gesprongen. Ook hier geldt dat met de huidige IC's extra +hardware nodig zal zijn om het te realiseren, maar het is in +het verleden toch een veel gebruikte methode geweest. Als +iemand het dus over vektor interrupts heeft, dan weet je nu +waar hij het over heeft. + + +## E V E N E E N A A N T A L F E I T E N + +Laten we nu eerst maar eens opsommen wat we precies weten. + +Een interrupt wordt altijd geaccepteerd, maar niet nood- +zakelijk gehonoreerd. Dit is het geval als de interrupts uit +staan (DI). + +Indien er twee interrupts optreden van dezelfde bron terwijl +de eerste nog niet gewist is door de CPU, dan zal de tweede +verloren gaan. Deze situatie komt echter ERG weinig voor. + +Als de interrupt gehonoreerd wordt, zal hardwarematig een DI +gegeven worden en het is aan de schrijver van de ISR om weer +een EI te geven (aan het eind van de routine bv.) Het is +mogelijk dat een interrupt geaccepteerd wordt terwijl de +interrupts uit staan. + +Bij een normale INT zal er naar adres 38H gesprogen worden. + +De bron van de int. zal zo snel mogelijk verteld moeten +worden dat de int. geaccepteerd is. De manier van de VDP die +het INT bit zelf wist als S#0 gelezen wordt is trouwens heel +standaard. De meeste chips die interrupts kumnen genereren +werken op deze manier omdat het makkelijk en snel is. + +Als een EI instruktie gegeven wordt zullen de interrupts +niet meteen aktief worden. Ze worden feitelijk pas +ingeschakeld na de instruktie die op de EI volgt. Op deze +manier kan je dus eerst nog een RET doen na een EI voordat +een geaccepteerde int. gehonoreerd wordt. + + +## N M I + +De Z80 heeft echter nog een interrupt die bij alle modes +aanwezig is, maar die op de MSX niet aangesloten is. Het is +de Non Maskable Interrupt die op bijna elke processor te +vinden is en ook meestal dezelfde naam heeft. Deze interrupt +is niet uit te zetten en heeft de op ��n na hoogste +prioriteit van alle interrupts. Als een NMI en een INT +tegelijkertijd optreden, dan zal eerst de NMI afgehandeld +worden. Omdat de NMI niet uit te zetten is zal een NMI +altijd meteen gehonoreerd worden tenzij er een busrequest +optreedt (dit is nl. ook een soort int. maar deze heeft de +allerhoogste prioriteit). + +Als een NMI optreedt, dan zal de Z80 zelf een DI uitvoeren, +maar hij bewaart de stand van de ints op het moment van +acceptatie. Na afhandeling van de NMI (die naar adres 66H +springt) zal de Z80 zelf de interrupt status terugzetten. +Als de ints dus uit stonden voordat de NMI optrad, dan +blijven ze ook uit na de afhandeling van de NMI en andersom. +De NMI moet afgesloten worden met de RETN instruktie en niet +met een RET omdat een RETN die oude int. status hersteld. +Bij een normale int. mag je geen RETN geven, want dat heeft +geen zin en kan alleen tot fouten leiden. + +Een vriend van me heeft al eens een schakelaar op de NMI +aangesloten en dat werkt prima. Hij kan dus met een druk op +de knop een routine starten die hij zelf eerst op de NMI +HOOK heeft gezet. Dit is erg leuk, maar het kan bij het +laden van disk problemen veroorzaken. Voor de hardwaremannen +onder ons is het toch een leuk en simpel projekt om eens te +doen. + + +## R E T I + +Veel mensen weten van het bestaan van deze instruktie, maar +er zijn er maar weinig die weten waar hij voor dient. Welnu, +deze instruktie is helemaal gelijk aan een normale RET +instruktie met het verschil dat hij een andere OPCODE heeft. +Zo zou een randapparaat dus kunnen kijken wanneer de CPU +klaar is met het afhandelen van een ISR door de databus te +scannen. Deze methode is bij mijn weten nog nooit gebruikt. +Het gebruik ervan is echter best handig omdat je zo heel +snel een ISR routine kunt herkennen. + + +## E I O F D I + +Heb je dat nu ook wel eens dat je wilt weten of op een +bepaald moment de ints aan of uit staan ?? Lang werd er +gedacht dat dit niet te testen is, maar dat is niet waar. +Het volgende programma kan dit testen: +``` + LD A,R ; Het werkt ook met LD A,I + PUSH AF + POP BC + BIT 2,C + JR Z,INTUIT +INTAAN: . + . +``` +In bit 2 van het F-register staat na een LD A,R de inhoud +van de IFF flip-flop. Dit bit wordt 0 gemaakt bij een DI +instruktie en 1 bij een EI. + + +## D E E I G E N I S R + +Om een kompleet eigen ISR te kunnen schrijven is het nodig +om de BIOS weg te halen en deze door RAM te vervangen. Zo +kan je zelf bepalen wat er vanaf adres 38H komt te staan, +maar voor de rest is het precies hetzelfde principe als bij +de normale MSX-ISR. Deze methode heeft alleen maar zin als +je HEEEL snel op een int. wilt reageren (bv. als je 40 +screensplits op je scherm wilt toveren). Je kunt nl. +beslissen om alleen de registers te PUSHen die je gaat +veranderen en niet de hele meute zoals de standaard ISR +doet. + + +## S L I M M E T R U C + +Bij screensplits is het te voorspellen welke screensplit aan +de beurt is door een soort tellertje bij te houden. Stel je +nu eens voor dat je meerdere ISR's hebt die aangeroepen +moeten worden voor de verschillende screensplits. Als er nu +eens een manier was om voordat een int. optreedt vast te +stellen waar deze heen moet springen (als deze uiteindelijk +optreedt) dan zou dat een behoorlijke respons snelheidswinst +betekenen. Het enige probleem dat hierbij om de hoek komt +kijken is de ISR zelf. Het adres waar heen gesprongen moet +worden staat in het RAM. Dus deze waarde moet ingelezen +worden, maar hoe doe je dat nu zonder uiteindelijk een +register te veranderen (iets dat immers niet mag in een ISR) +Welnu, laat ik eerst maar de oplossing geven en daarna nog +wat verdere uitleg. +``` +0038H PUSH HL +0039H LD HL,(ISRPNT) ; De ISR pointer +003CH EX (SP),HL +003DH RET + +00F0H ISRPNT: DW &HFD9A ; Het pointeradres +``` +HL moet op de stack gezet worden omdat je anders de pointer +niet uit kan lezen. De EX (SP),HL draait de pointer en de +oude waarde van HL echter om zodat het programma ook te +beschrijven is als: +``` + PUSH (ISRPNT) + RET +``` +of: +``` + JP (ISRPNT) +``` +Deze laatste twee oplossingen kunnen echter niet +gerealiseerd worden omdat de Z80 deze instrukties niet kent. +In principe doen ze echter hetzelfde. Het resultaat van dit +alles is dus dat je voordat een int. optreedt kunt bepalen +waar deze heen moet springen en deze sprong uit kunt voeren +zonder een register van waarde te veranderen. De RET +instruktie van de echte oplossing verhoogt de SP immers ook +weer naar zijn oude waarde, dus het enige dat verandert is +de PC (Program Counter) en dat was nu juist de bedoeling. + +De responstijd is zo goed omdat je weet welke en wat voor +interrupt op zal gaan treden zodat je ook het feitelijke +pollen kunt doen voordat de int. optreedt. Als er dan +uiteindelijk een int optreed hoef je alleen nog maar naar de +juiste ISR te springen en is alle informatie al voorbereid. +Je moet echter goed oppassen dat je de tel niet kwijt raakt +omdat het dan dus echt een puinhoop wordt. Zorg er dus voor +dat de ints. zoveel mogelijk aan staan (ook om de +responstijd hoog te houden). + + +## D E F E I T E L I J K E I S R + +Hier is nu nog maar weinig over te vertellen. Het enige dat +je hier extra moet doen t.o.v. de standaard ISR is het +PUSHen van registers die je gaat veranderen oftewel: +``` +0038H JP ISR + +0100H ISR: PUSH AF + PUSH xx + . + IN A,(&H99) ; Is het een 50/60 Hz signaal?? + . + . + POP xx + POP AF + RET ; Einde van int. afhandeling +``` + +## B I O S W E G ? ? + +Dat is heel simpel met de volgende routine: +``` + LD A,(&HF341) + LD H,0 + CALL &H24 ; Zet RAM over BIOS + LD A,RAMPGE + OUT (&HFC),A + [ Initialiseer de ISR ] + EI +``` +Nu staat mapper page RAMPGE vanaf adres 0000H tot 3FFFH. Je +hoeft nu alleen nog maar de ISR af te buigen en je bent +klaar voor aktie. Na een CALL op adres &H24 staan de +interupts overigens uit, en het is aan de gebruiker om deze +daarna weer aan te zetten. + +Goed, de eigen ISR is ge�nstalleerd, maar hoe krijgen we nu +de BIOS weer terug?? Met CALL &H24 gaat dat niet, want die +is immers weggehaald!! Het zelf schakelen van sloten is een +mogelijkheid, maar er is een simpeler manier. Op deze disk +staat de assembly listing "ENASLT.ASM" waar de complete CALL +&H24 in nagemaakt is. Voeg deze routine simpelweg aan je +eigen programma toe en gebruik hem inplaats van CALL &H24. +Alle schakelproblemen zouden dan opgelost moeten zijn. Om de +BIOS weer terug te krijgen moet je het volgende intikken. +``` + LD A,(&HFCC1) + LD H,0 + CALL ENASLT ; Dus niet CALL &H24 +``` + +Hopelijk zijn jullie iets nieuws te weten gekomen uit deze +informatie en moet het mogelijk zijn om eens lekker ISR's te +kunnen gaan maken. Het resultaat zie ik dan wel op bv. de +Sunrise Picturedisk!! + +Alex van der Wal diff --git a/Sunrise Special/2/Ledjes.md b/sunrise_special/2/ledjes.md similarity index 100% rename from Sunrise Special/2/Ledjes.md rename to sunrise_special/2/ledjes.md diff --git a/sunrise_special/2/macro_commandos_met_gen80.md b/sunrise_special/2/macro_commandos_met_gen80.md new file mode 100644 index 0000000..030e847 --- /dev/null +++ b/sunrise_special/2/macro_commandos_met_gen80.md @@ -0,0 +1,258 @@ +# M A C R O C O M M A N D O - S M E T G E N 8 0 + + +## W A T I S E E N M A C R O ? + +Je kunt macro's gebruiken om je assemblercode een stuk +flexibeler en overzichtelijker te maken. Een macro kun je +zien als een extra commando dat door de assembler in een +aantal andere instructies wordt omgezet. + +Nu zeg je: Dat is toch onzin. Het is toch veel duidelijker +om gewoon de instructies te gebruiken. Ja, dat kan ook wel +zo zijn, maar als je 10 keer dezelfde instructie moet +gebruiken en een CALL is niet handig of mogelijk, is het +gebruik van macro's een mooi alternatief. En het is nog +makkelijk aan te passen ook. + +Noot: Alleen GEN80 en Microsoft M80 werken, voor zover ik +weet, met macro's. WBASS2-gebruikers kunnen of deze tekst +niet lezen of een andere assembler gaan aanschaffen. + + +## H E T G E B R U I K + +Met macro's is het omzetten van de source van een BLOAD-file +naar een .COM-file een koud kunstje. Het label BDOS had je +natuurlijk al aan het begin gedefinieerd met +``` + BDOS: EQU #F37D +``` +en dan hoef je #F37D alleen maar in het begin te veranderen +in 5 (of andersom als je van MSX-DOS naar BASIC wil). + +Maar dan moet je ook de BIOS-commando's omzetten. Meestal is +dat dan een kwestie van zoeken en vervangen (in TED). Maar +als je macro's gebruikt had was het een karweitje van ��n +twaalfhonderdste uur (oftewel 3 seconde) geweest. + +Ik gebruik in mijn eigen sources altijd ��n van de volgende +macro's: +``` + BIOS: MACRO @FNC ;Voor MSX-DOS + LD IX,@FNC + LD IY,(#FCC0) + CALL #001C + ENDM + + BIOS: MACRO @FNC ;Voor BASIC + CALL @FNC + ENDM +``` +Het is dan een koud kunstje om een BIOS-funktie aan te +roepen vanuit een .COM-file. En last but not least, het +wordt een heel stuk duidelijker: +``` + LD IX,#0180 + LD IY,(#FCC0) + CALL #001C +``` +of +``` + BIOS #0180 +``` + +## C O M M A N D O - S + +Ik werk zelf alleen nog maar met GEN80. (Ik heb eerst met +WBASS2 gewerkt, maar toen ik GEN80 door had, was ik +verkocht.) Ik bespreek dit dan ook met de commando's en +voorbeelden die in de handleiding van GEN80 staan. M80 +werkt, denk ik, precies hetzelfde, maar je weet maar +nooit... + +Uit het bovenstaande voorbeeld zal grotendeels duidelijk +zijn hoe een macro moet worden gedefinieerd. Maar voor de +zekerheid staat het hieronder iets beter. + +MACRO: De naam van het macro geef je op aan het begin van + de regel. Dan zet je daar MACRO achter en de + eventuele te gebruiken variabelen: + + [macro] MACRO @var1(,@var2,...,@varX) + + De variabelen met een apestaartje ("@") erin, zijn + lokale variabelen. Die komen verder ook niet in de + .SYM-file terecht en worden alleen gebruikt als + input. + +ENDM: Je be�indigt een macro met het commando ENDM, dat + (natuurlijk) staat voor END of Macro. + +DEFL: Met DEFL kan een label een waarde worden gegeven IN + een macro. + +IF: Met IF kun je voorwaardelijk assembleren. Als de + waarde van de uitdrukking ongelijk aan 0 is worden + de instructies op de regels na IF uitgevoerd tot aan + ELSE of ENDC. + IFs zijn nestbaar tot een diepte van 8. +COND: Gelijk aan IF. + +ELSE: Dit commando komt voor ENDIF en na IF. Als de + uitdrukking achter IF wel 0 is, worden de commando's + op de regels na ELSE uitgevoerd tot aan ENDIF. + +ENDC: Dit geeft het einde van een voorwaardelijk gedeelte + aan. +ENDIF: Gelijk aan ENDC. + + +## V O O R B E E L D E N + +Alle voorbeelden staan ook in de file MACRO.LIB. Je kunt dan +de macro's die je nodig hebt daaruit halen. +De volgende voorbeelden komen uit de handleiding van GEN80: +``` + BC_DE: MACRO @PARAM1, @PARAM2 + LD BC,@PARAM1 + LD DE,@PARAM2 + ENDM +``` +De instructie +``` + BC_DE #4444,-5 +``` +zal door GEN80 worden omgezet in de assembler-instructies +``` + LD BC,#4444 + LD DE,-5 +``` + +## E X C H A N G E +``` + EXCH: MACRO @REG1,@REG2 + IF @REG1=HL .AND. @REG2=DE + EX DE,HL + ELSE + IF @REG1=DE .AND. @REG2=HL + EX DE,HL + ELSE + PUSH @REG1 + PUSH @REG2 + POP @REG1 + POP @REG2 + ENDIF ;Niet vergeten! + ENDM +``` +Er wordt eerst gekeken of @REG1 HL en @REG2 DE is. In dat +geval is EX DE,HL een kortere en snellere oplossing. +Natuurlijk moet ook worden gecontroleerd of @REG1 DE en +@REG2 HL is. +Is dat niet het geval dan worden de registerparen volgens de +bekende (ja toch?) manier verwisseld. + +Met dit macro is het verwisselen van twee registerparen een +koud kunstje en hoeft er niet meer worden gedacht aan EX +DE,HL. Alleen SP kun je niet gebruiken. Om nu 2 +registerparen te verwisselen hoef je alleen maar EXCH +reg1,reg2 in te geven en bovenstaand macro in je source +zetten. + + +## A B S O L U T E W A A R D E +``` + ABS MACRO + OR A + JP P,ABS@SYM + NEG + ABS@SYM: + ENDM +``` +Dit macro maakt A altijd positief. Als al A positief is dan +wordt er doorgeJumPt naar het einde van het macro (dat is +dan de instructie na het macro). + +@SYM wordt omgezet in een hexadecimaal getal van 4 cijfers. +Dit macro was anders niet te maken. Het zorgt er ook voor +dat de naam van het label verandert met de recursiediepte. +Ook was anders recursie in ��n macro zo goed als +onmogelijk... + + +## F A C U L T E I T +``` + FACT: MACRO @RESULT,@N + IF @N=1 + @RESULT DEFL 1 + ELSE + FACT T@SYM,@N-1 + @RESULT DEFL T@SYM*(@N) + ENDIF + ENDM +``` +Dit macro geeft een label een faculteit van een getal mee. +Helaas werkt het maar tot 6 faculteit. Het werkt vrij +ingewikkeld en je kunt beter gewoon 120 invullen in plaats +van dit macro te gebruiken, maar het is wel een mooi +voorbeeld. +``` + FACT: MACRO @RESULT,@N +``` +Dit definieert het macro FACT en de lokale variabelen +@RESULT en @N zijn de lokale variabelen. +``` + IF @N=1 + @RESULT: DEFL 1 +``` +Als er naar 1 faculteit gevraagd wordt geef dan gewoon ��n +terug. +``` + ELSE + FACT T@SYM,@N-1 +``` +Indien niet aan @N=1 voldaan wordt, wordt FACT nog eens +aangeroepen met als faculteit ��n minder en het label hangt +af van de recursiediepte (@SYM, zie boven). +``` + @RESULT: DEFL T@SYM*(@N) + ENDIF + ENDM +``` +Het label dat achter FACT bij het aanroepen staat krijgt de +waarde van de vorige variabele vermenigvuldigd met het +faculteitsgetal. + + +## B D O S +``` + BDOS: MACRO @FN1,@FN2 + IF "@FN2">"" + LD DE,@FCB + ENDC + LD C,@FN1 + CALL 5 + ENDM +``` +Dit macro maakt het aanroepen van de BDOS iets makkelijker: +``` + BDOS 9,Tekst +``` +is bijv. genoeg om de tekst achter het label Tekst op het +scherm te laten komen. +Maar mensen die MSX-DOS 2 gebruiken hebben eigenlijk niks +aan dit macro. MSX-DOS 2 heeft meestal wel meer dan ��n +input register(paar) nodig. + + +# V R A G E N , O P M E R K I N G E N ? + +Schrijf naar: + Stichting Sunrise + t.a.v. Kasper Souren + Postbus 2146 + 2400 CC Alphen aan den Rijn + +Of bel Sunrise BBS Nuth. + +Kasper Souren diff --git a/sunrise_special/2/memman_2.42.md b/sunrise_special/2/memman_2.42.md new file mode 100644 index 0000000..a11728f --- /dev/null +++ b/sunrise_special/2/memman_2.42.md @@ -0,0 +1,76 @@ +# M E M M A N 2 . 4 2 + + +In de speciale MemMan rubriek op de Special mag de nieuwste +versie van MemMan natuurlijk niet ontbreken. Eerst maar even +wat er allemaal nieuw is in deze nieuwe versie... + + +## W A T I S N I E U W ? + +1 - Voor mensen die de 32 kB RAM willen kunnen aansturen die + in BASIC achter de ROM's zitten, is er de functie GetTPA + toegevoegd. +2 - Voor HD-gebruikers wordt er een mogelijkheid geboden om + de TSR's makkelijker in te laden: in het environment + item TL dient de drive en de subdirectory te worden + opgegeven. Daarna kijkt TL niet alleen in de huidige + directory, maar ook de met TL aangegeven directory. +3 - Met TV.COM kun je nu ook zien in welk segment de diverse + TSR's zich bevinden. Zo kun je precies zoveel TSR's + wissen dat ��n segment vrijkomt. +4 - De stack van MemMan is nu in te stellen en/of uit te + lezen met de functies GetMMSP en SetMMSP. Tot nog toe + gebruikt alleen Tracer, die er al op voorbereid was, + deze mogelijkheid. +5 - In BASIC kun je nu een overzicht krijgen van de extra + commando's die de TSR's je verschaffen door CMD HELP in + te tikken. Tracer was (ook) hier op voorbereid. Maar ook + het ingebouwde MSX TsrUtils is er mee uitgerust. + Helaas moet de TSR dat wel zelf opvangen, het zou mooier + geweest zijn wanneer je, als programmeur, de gewenste + tekst in de TSR op een bepaalde plaats zet, zodat MemMan + CMD HELP afwerkt. +6 - TSR's kunnen MemMan nu aanroepen door naar #4002 te + springen; daar zit een MemMan entry. Hierdoor worden ze + sneller en kleiner. +7 - IniChk laat de functieafhandelingsroutine van MemMan nu + in HL achter. Daarna is een JP (HL) voldoende om naar + MemMan te springen. Maar TSR's hebben het, zoals in punt + 6 besproken, makkelijker. + + +## H O E K O M J E E R A A N ? + +Heel simpel te beantwoorden: Op deze disk staat MEMM242.PMA. +Deze library bevat alle 13 bestanden die bij MemMan 2.42 +behoren. O.a. een nieuwe versie van BK, de oude kon niet met +meer dan 4 MB overweg. + +Als je geen MSX-DOS 2 hebt, kopieer MEMM242.PMA en PMEXT.COM +dan naar een lege diskette (of een diskette met nog +voldoende ruimte) en typ het volgende in: + +PMEXT MEMM242 A: + +Als je MSX-DOS 2 hebt kan het veel sneller door de RAMdisk +te gebruiken. Maak een RAMdisk aan en doe vervolgens de +Special diskette in de drive. Typ nu het volgende in: + +PMEXT MEMM242 H: + +Na afloop natuurlijk wel nog even de files naar een diskette +kopi�ren. + + +## D A T U M E N T I J D + +Leuk aan MemMan is dat ze de datum en tijd van de files +aanpassen. Bij de meeste files is de tijd op 2:42 gezet, en +de datum op 19/09/92, de releasedatum van deze MemMan. + +Voor uitleg en technische specificaties bij MemMan verwijs +ik u naar de tekstfiles in MEMM242.PMA. + +Stefan Boer +Kasper Souren diff --git a/sunrise_special/2/msx-dos_2.31.md b/sunrise_special/2/msx-dos_2.31.md new file mode 100644 index 0000000..fef7cf3 --- /dev/null +++ b/sunrise_special/2/msx-dos_2.31.md @@ -0,0 +1,186 @@ +# M S X - D O S 2 . 3 1 + + +Bij de Panasonic FS-A1GT wordt MSX-DOS 2.31 geleverd in het +ROM. Veel mensen denken dat DOS 2.31 alleen zorgt voor de +ROM- en SRAMdisk, en dus voor MSX-View. Dat bleek toch niet +waar te zijn: + + +## S R A M D I S K Z O N D E R M S X - V I E W + +Veel mensen vroegen zich (en anderen...) af hoe ze de +SRAMdisk van de GT konden gebruiken zonder MSX-View van de +ROMdisk op te hoeven starten. +Door mijn nieuwsgierige aard heb ik even TYPE C:AUTOEXEC.BAT +ingetikt bij een GT-user. Wat ik daar zag was natuurlijk een +opluchting voor de GT'er: +IF EXIST %SRAMD%\AUTOEXEC.BAT %SRAMD%\AUTOEXEC.BAT + +In menselijke taal wordt dat: +Als de file AUTOEXEC.BAT op de SRAMdisk staat, moet die +batchfile uitgevoerd worden. + +De mensen die bovenstaande vraag hadden, kunnen zich nu voor +het hoofd slaan, of natuurlijk gewoon een file genaamd +AUTOEXEC.BAT op de SRAMdisk plaaten. +Op deze disk staat een file die ook in BBS'en heeft gestaan. +De file schakelt de ROM-mode en copieert de Europese +karakterset naar het RAM. En dan wordt weer teruggeschakeld +naar DRAM-mode. + +De werking is als volgt: Bij een reset worden de systeemROMs +naar RAM gecopieerd, door naar de ROM-mode te schakelen +worden die RAM-pagina's weer vrijgegeven voor "hardnekkige" +software. De BIOS wordt vervolgens aangepast door de +Europese karakterset te copi�ren over de Japanse karakterset +heen. Dan wordt de DRAM-mode teruggeschakelt, en worden de +ROMs niet meer over de RAM heengecopieerd. Dit programma +leent zich uitstekend om op de SRAMdisk gezet te worden. Dat +staat ook in DOS231.PMA. + +Met "hardnekkige" software bedoel ik software die niet +volgens de standaard MSX-DOS 2 mapperroutines werkt. +Eigenlijk moeten die memory mapper plaatsen worden +vrijgegeven met FreSEG. Op deze disk staat een programmaatje +uit MSX-Magazine 1 van 1990 genaamd ROMTURBO.COM. Door dit +te runnen wordt de ROM-mode ingeschakeld en de +mappersegmenten die eerst door de DRAM werden gebruikt weer +vrijgegeven. Voor meer informatie over DRAM-mode raad ik aan +om Sunrise Special #1 nog eens te lezen, en dan vooral het +artikel over de R800. +N.B. Het broertje van ROMTURBO, RAMTURBO, staat ook op deze +disk. + + +## E N V I R O N M E N T I T E M S + +DOS 2.31 kent de mijns inziens zeer interessante +mogelijkheid om Environment Items (vanaf nu gewoon items) te +gebruiken in batchfiles. + +Je kunt dan, zij het zeer beperkt, programmeren in +batchfiles. Een zeer simpel virus zou mogelijk zijn. +Het benoemen van items zal iedereen wel duidelijk zijn nu. +Dat gaat gewoon met SET. Voorbeelden volgen zometeen. + +Maar je kunt ze nu ook gebruiken voor alle andere +doeleinden: Gewoon laten voorgaan en volgen door een +%-teken. Je krijgt dan bijv. %SRAMD% voor drivenaam die de +SRAMdisk heeft. Dat kun je dus ook veranderen met SET. (SET +SRAMD=drivenaam:). (Nee, geen dwerg-smiley, maar een dubbele +punt.) + + +## I F + +Met IF == kun je tekst vergelijken. Tekst vergelijken is +niet echt zo interessant. Maar de kracht van deze functie is +dat items met %-tekens eromheen als tekst gezien worden in +batchfiles. +Je kunt ook kijken of een file wel bestaat: + + +## E X I S T + +Met IF EXIST kun je erachter komen of een bepaalde file +bestaat. Bovenaan, in de regel uit AUTOEXEC.BAT van de +ROMdisk, staat het ook al. De werking is zeer simpel. Als +een file bestaat wordt gewoon het commando wat erop volgt +uitgevoerd. De file volgt gewoon achter IF EXIST. + + +## N O T + +Met NOT geef je een negatie aan. Je kunt dus IF NOT EXIST +filenaam.ext enz. gebruiken. + + +## E E N V O O R B E E L D + +Ik gebruik zelf een paar leuke batchfiles om mijn leven als +HD-gebruiker te vergemakkelijken. Als je maar weinig +opslagruimte hebt, heeft het eigenlijk weinig nut. Meestal +doe je dan toch weinig in DOS. Maar voor een HD-user die +GUI's niet handig vindt, wordt het allemaal wat aangenamer +met batchfiles. Bij een Turbo R zul je het nauwelijks +merken, maar bij een 3.58 MHz Z80 zal de snelheid flink +afnemen door het gebruik van deze batchfile. Voor 7 +MHz-gebruikers zal het nog wel te doen zijn. + + +## T E D . B A T + + CLS + +Schoon scherm. Ligt aan je persoonlijke wensen. + + IF NOT %1NIKS==NIKS SET TEDFILE=%1 + +Als %1 plus NIKS NIET gelijk is aan niks, wordt TEDFILE aan +%1 gelijk gemaakt. Zorgt ervoor dat de naam hetzelfde blijft +als je geen parameter opgeeft. Zeer handig bij het debuggen +van een machinetaalprogramma! + + IF NOT EXIST %TEDFILE% SET TEDFILE= + +Als %TEDFILE% NIET bestaat wordt %TEDFILE% gewist. + + IF EXIST %TEDFILE%.MAC SET TEDEXT=.MAC>NUL + IF EXIST %TEDFILE%.GEN SET TEDEXT=.GEN>NUL + IF EXIST %TEDFILE%.BAT SET TEDEXT=.BAT>NUL + IF EXIST %TEDFILE%.DOC SET TEDEXT=.DOC>NUL + IF EXIST %TEDFILE%.TXT SET TEDEXT=.TXT>NUL + +Er wordt gekeken of de file bestaat met een van de 5 +extensies. Dit is natuurlijk naar wens in te stellen. Het +gaat trouwens van minst belangrijke naar belangrijkste. Als +er bijv. een .GEN- en een .DOC-file bestaan wordt de +.DOC-file ingeladen. Die staat immers iets lager. +>NUL wordt opgegeven om de evt. foutmeldingen niet op het +scherm te laten komen. Zie voor meer uitleg de tekst over +redirection en pipelining op deze disk. + + SET TEDEXE=A:\TED\TED.COM + IF %TEDEXT%==.MAC SET %TEDEXE%=A:\TED\MLTED.COM + IF %TEDEXT%==.GEN SET %TEDEXE%=A:\TED\MLTED.COM + %TEDEXE% %TEDFILE%%TEDEXT% + +Het opstarten van TED. Voor %TED% is de directory plus de +naam die TED heeft. Door deze constructie te gebruiken kun +je verschillende versies van TED gebruiken, die je met +hetzelfde commando opstart. MLTED is bij mij een versie met +de instellingen (zoals TAB's) ingesteld voor machinetaal. +Als TED.BAT en TED.COM in dezelfde directory staan zal +TED.COM worden ingeladen als het commando "TED" wordt +ingetikt. Daarom MOET TED.COM in een andere directory staan +als deze batchfile gebruikt worden. Of je moet iedere keer +TED.BAT filenaam intikken. En het was nu juist om het +makkelijker te maken. Je kunt natuurlijk ook, om het +helemaal makkelijk te maken de batchfile T.BAT noemen. Dan +hoef je maar een letter in te tikken als je net uit TED zelf +komt. + + +Op deze disk staan: + +ROMTURBO.COM Programma om de 64 kB RAM die de DRAM-mode + inpikt toch te kunnen gebruiken. Dit gaat + volgens de standaard: De segmenten die door de + DRAM-mode worden gebruikt worden met de + standaard MSX-DOS 2 mapper-routines + vrijgegeven. + +RAMTURBO.COM Programma dat de DRAM-mode volgens de + standaard installeert. Als er niet genoeg + geheugen meer is, wordt een melding gegeven. + +KARSET.COM Programma dat de Europese karakterset in de + DRAM zet. Er zit geen puntje, maar een + streepje door de nul. In de oorspronkelijke + versie was het een puntje. + +TED.BAT De batchfile van het voorbeeld. + + +Kasper Souren \ No newline at end of file diff --git a/sunrise_special/2/msx-dos_2_voor_machinetaalprogrammeurs.md b/sunrise_special/2/msx-dos_2_voor_machinetaalprogrammeurs.md new file mode 100644 index 0000000..178efe5 --- /dev/null +++ b/sunrise_special/2/msx-dos_2_voor_machinetaalprogrammeurs.md @@ -0,0 +1,428 @@ +# C U R S U S M S X - D O S 2 V O O R M A C H I N E T A A L P R O G R A M M E U R S + + +Op deze Sunrise Special start ik een cursus waarin ik de +vele mogelijkheden van MSX-DOS 2 zal beschrijven. Ik zal +proberen door middel van voorbeelden de nieuwe DOS-CALL's +duidelijk te maken. De cursus zal uit ongeveer zes delen +bestaan met op deze disk het eerste deel. In dit eerste deel +zal ik de programma-omgeving beschrijven die MSX-DOS 2 voor +programma's biedt. + + +## H E T T P A - G E H E U G E N + +TPA staat voor Transient Program Area. Een Transient Program +(TP) is een moeilijk woord voor een normale COM-file. Deze +COM-files worden door COMMAND2 ingeladen op adres #0100 en +vervolgens geCALLed met de stackpointer (SP) aan het einde +van het TPA. Al het geheugen tot aan de stack mag gebruikt +worden door het TP. De inhoud van de Z80-registers is niet +gedefinieerd. De eerste 256 bytes van het RAM hebben een +speciale betekenis. Deze bytes zal ik dadelijk verklaren. +Interrupts staan aan als een TP aangeroepen wordt door +COMMAND2 en moeten in het algemeen aan blijven staan. +MSX-DOS function-calls zullen meestal de interrupts +aanzetten als ze uitstonden. + + +## T E R U G K E E R N A A R M S X - D O S + +Een TP kan zichzelf be�indigen door middel van een van de +onderstaande manieren: + +1 Terugkeren d.m.v. RET, met de originele SP. +2 JumP naar adres #0000. +3 MSX-DOS "Program Terminate" function call. +4 MSX-DOS 2 "Terminate with Error Code" function call. + +De eerste drie zijn identiek met CP/M en MSX-DOS 1. De +laatste is een nieuwe functie van MSX-DOS 2. Met deze +functie kan een programma een foutmelding teruggeven aan +COMMAND2 die deze zal afdrukken op het standaard device CON +(NvdR: Hoeft niet per se CON te zijn, kan ook PRN of NUL +zijn). Deze functie zal geen foutmelding afdrukken als de +error code gelijk is aan nul. Vele andere acties kunnen het +programma dwingen af te breken, waaronder onder andere het +drukken van CTRL-C, CTRL-STOP of het kiezen van de optie +Abort als er een diskerror optreedt. Een TP kan een "abort +routine" definieren, die deze gevallen kan opvangen. + + +## A D R E S # 0 0 0 0 T O T # 0 1 0 0 + +In de eerste 256 bytes van het geheugen worden door COMMAND2 +enige parameters gezet voor het TP. De indeling van deze +eerste bytes is als volgt. +``` + +0 +1 +2 +3 +4 +5 +6 +7 + +-----+-----+-----+-----+-----+-----+-----+-----+ +#0000 | Reboot Entry | Reserved | MSX-DOS Entry | + +-----+-----+-----+-----+-----+-----+-----+-----+ +#0008 | RST #08: ongebruikt | RDSLT routine Entry | + +-----+-----+-----+-----+-----+-----+-----+-----+ +#0010 | RST #10: ongebruikt | WRSLT routine Entry | + +-----+-----+-----+-----+-----+-----+-----+-----+ +#0018 | RST #18: ongebruikt | CALSLT routine Entry | + +-----+-----+-----+-----+-----+-----+-----+-----+ +#0020 | RST #20: ongebruikt | ENASLT routine Entry | + +-----+-----+-----+-----+-----+-----+-----+-----+ +#0028 | RST #28: ongebruikt | ongebruikt | + +-----+-----+-----+-----+-----+-----+-----+-----+ +#0030 | CALLF routine entry | ongebruikt | + +-----+-----+-----+-----+-----+-----+-----+-----+ +#0038 | Interrupt vector | | + +-----+-----+-----+-----+ + +#0040 | | + + + +#0048 | Gebruikt door slot switching code | + + + +#0050 | | + + +-----+-----+-----+-----+ +#0058 | | | + +-----+-----+-----+-----+ + +#0060 | Ongeopend FCB van de eerste parameter | + + +-----+-----+-----+-----+ +#0068 | | | + +-----+-----+-----+-----+ | +#0070 | Ongeopend FCB van de tweede parameter | + + +-----+-----+-----+-----+ +#0078 | | Ruimte voor FCB-data | + +-----+-----+-----+-----+-----+-----+-----+-----+ +#0080 | | + . . + . Default DMA-adres . + . Hier staat de originele commando line . + . . + . . +#00F8 | | + +-----+-----+-----+-----+-----+-----+-----+-----+ +``` +Op adres #0000 staat de jump, die gebruikt wordt voor het +be�indigen van een programma. Deze jump kan ook gebruikt +worden om de BIOS jump vector te vinden. (Zie verderop). De +lage byte van dit adres zal altijd #03 zijn voor de +compatibiliteit met CP/M. + +De twee gereserveerde bytes op adres #0003 en #0004 zijn de +IO-byte en de Current Drive/User byte in CP/M. Hoewel +MSX-DOS 2 deze byte altijd up-to-date houdt, wordt het niet +aanbevolen om in nieuwe programma's deze byte te gebruiken. +Deze kunnen beter de MSX-DOS 2 function call "Get current +drive" gebruiken. Het IO-byte wordt niet ondersteund, omdat +MSX-DOS 2 device-IO anders geregeld heeft dan CP/M. + +Op adres #0005 staat een jump naar de start van de +BDOS-verwerking van MSX-DOS 2. Dit jumpadres bepaalt de top +van het TPA. De grootte van het TPA hangt af van de +uitbreidingen die u gebruikt, maar is standaard 53 kB. De +lage byte van dit adres zal altijd #06 zijn voor de +compatibiliteit met CP/M. De zes bytes direct hierachter +bevatten het CP/M-versienummer en een serienummer. + +Er zijn vier bytes gereserveerd voor de gebruiker op elk +Z80-restart adres. De bytes tussen de restart adressen zijn +entry's voor enkele MSX slot switching routines. + +Het hele gebied van #0038 tot #005C wordt gebruikt voor de +interruptafhandeling in slot switching code. + +De twee FCB's op adres #005C en #006C zijn de eerste twee +parameters achter de commandonaam, gezien als filenamen. Als +beide FCB's gebruikt worden moet de tweede naar een andere +locatie gekopieerd worden, want als de eerste geopend wordt, +zal die de tweede overschrijven. + +De gehele commandoline, zonder commandonaam, wordt bewaard +in het standaard DMA gebied (vanaf #0080) met als eerste +byte een lengtebyte en als laatste byte een nul. (Noch de +lengtebyte noch de nul worden meegeteld in de lengte). De +commandoline zal geheel uit hoofdletters bestaan als het +environment item "UPPER" op "ON" gezet is. De commandoline +zal niet ontdaan worden van inleidende spaties. + +Nieuwe programma's kunnen de oude FCB's beter niet meer +gebruiken. Er zijn in MSX-DOS 2 andere, simpelere functies +beschikbaar. Deze functies maken het ook mogelijk met +subdirectory's te werken. + +Er is nog een manier om de commandoline uit te lezen. +COMMAND2 zet namelijk een environment item, "PARAMETERS" +genaamd, op die de commandoline bevat in zijn originele +staat. Het tweede environment item dat COMMAND2 op zet heet +"PROGRAM". Dit bevat het Drive\Path\Filenaam string dat gold +voor het geladen programma. + + +## D E B I O S J U M P T A B L E + +De jump op adres #0000 zal springen naar een adres dat ook +een jump bevat. Deze jump is de tweede entry in een jump +table van zeventien entry's. Dit komt exact overeen met +CP/M. + +De eerste acht entry's zijn voor reboot en karakter-IO. De +andere negen doen niets en geven, waar mogelijk, een +errorcode terug. + +MSX-DOS 2 zal bij een CALL overschakelen naar een interne +stack, zodat de userstack niet groter hoeft te zijn dan +ongeveer acht bytes. + +Overzicht BIOS jumptable: +``` +#xx00 Warm boot +#xx03 Idem +#xx06 Console status +#xx09 Console input +#xx0C Console output +#xx0F List output +#xx12 Punch output +#xx15 Reader input +#xx18 Geen functie +#xx1B Geen functie +#xx1E Geen functie +#xx21 Geen functie +#xx24 Geen functie +#xx27 Geen functie +#xx2A Geen functie +#xx2D List status +#xx30 Geen functie +``` + +## G E H E U G E N G E B R U I K + +Een TP mag zoveel slotswitching doen als het wil, als het +maar rekening houdt met de interrupts e.d. als het TP page +nul of drie wegschakelt. TP's moeten erg voorzichtig zijn +met het veranderen van page 0 en TP's mogen nooit +veranderingen aanbrengen in page 3. Page 0, 1 en 2 mogen in +elk slot zitten als het TP MSX-DOS 2 aanroept. Deze +instellingen zullen bewaard blijven. Een parameter kan via +elk slot aan MSX-DOS 2 worden doorgegeven. Dit geldt niet +voor de environmentstrings en de diskbuffers. Deze moeten +zich in de main mapper bevinden. Het is mogelijk om gegevens +in andere segmenten dan de originele TPA segmenten te laden. +Als het TP de memory mapper wil schakelen moet het daarvoor +gebruik maken van de mappersupportroutines in page 3. Deze +routines zal ik de volgende keer beschrijven. Een TP dat de +mapper schakelt moet er zelf voor zorgen dat de originele +TPA segmenten weer ingeschakelt worden, als het programma +eindigt. + + +## F I L E H A N D L E S + +File handles zijn de nieuwe verbeterde methoden om files aan +te spreken en te manipuleren. Een file handle is een byte +die betrekking heeft op een geopende file. Er wordt een +nieuwe file handle aangemaakt bij de aanroep van de MSX-DOS +2 functie "Open file handle" (#43) of "Create file handle" +(#44). De file handle kan gebruikt worden om data van de +file te lezen of data naar de file te schrijven. Een file +handle blijft bestaan totdat een van de volgende MSX-DOS 2 +functies wordt gebruikt: "Close file handle" (#45) of +"delete file handle" (#46). MSX-DOS 2 opent als het opstart +al enige file handles voor de standaard IO-kanalen. Deze +default file handles zijn: +``` +#00 Standaard input (CON) +#01 Standaard output (CON) +#02 Standaard error in/output (CON) +#03 Standaard auxiliary in/output (AUX) +#04 Standaard printer output (PRN) +``` +Een TP mag deze file handles sluiten, verwijderen of op een +andere manier beschadigen, omdat COMMAND2 deze file handles +automatisch zal herstellen. Ook als een TP zich niet netjes +gedraagt en niet alle file handles sluit, zal dit geen +probleem opleveren, omdat COMMAND2 dit zal doen. (Netjes is +anders). + + +## F I L E I N F O B L O C K S ( F I B ) + +Alle nieuwe MSX-DOS 2 functies die op files werken, kunnen +aangeroepen worden met een simpele pointer naar een string. +Deze string bevat dan de benodigde parameters afgesloten +door een nul. Dit soort strings noemt men ASCIIZ-strings. In +plaats van een ASCIIZ-string mag men ook een FIB doorgeven +aan MSX-DOS 2. FIB's zien er als volgt uit: +``` + 0 - Altijd #FF + 1..13 - Filename als ASCIIZ-string + 14 - File atributen +15..16 - Tijd +17..18 - Datum +19..20 - Eerste datacluster +21..24 - Grootte van de file + 25 - Logische drive (A: = 1) +26..63 - Interne informatie +``` +De #FF aan het begin van een FIB is als herkenning voor het +systeem dat het om een FIB gaat en niet om een platte +ASCIIZ-string. De interne informatie vanaf byte 26 mag nooit +verandert worden. De byte van de file atributen ziet er zo +uit: +``` +Bit 0 Read only +Bit 1 Hidden +Bit 2 System +Bit 3 Volume naam +Bit 4 Directory +Bit 5 Archive +Bit 6 Gereserveerd +Bit 7 Device +``` +De tijd en datum moet men zo coderen: +Tijd: Bits 15..11 Uren (0..23) + Bits 10...5 Minuten (0..59) + Bits 4...0 Seconden (0..58, even getallen) +Datum: Bits 15...9 Jaar (0..99, 1980 tot 2080) + Bits 8...5 Maand (1..12) + Bits 4...0 Dag (0..31) + +De filegrootte wordt opgeslagen als een 32-bit getal met de +lowbyte eerst. Deze byte is nul voor directory's. Deze FIB's +worden door de functie calls "Find first entry", "Find next +entry" en "Find new entry" ingevuld. + + +# F I L E C O N T R O L B L O C K S ( F C B ) + +Een FCB is 32 bytes lang en bevat de volgende informatie: +``` + #00 Drive nummer (A:=1, Default=0) +#01..#08 Filename +#09..#0B Filename extensie + #0C Bloknummer + #0D Attributen +#0E..#0F Record-lengte +#10..#13 Filegrootte +#14..#17 Volume-ID (DOS 2) Time/Date (DOS 1) +#18..#1F Interne informatie + #20 Current record +#21..#24 Random recordnummer +``` +Het wordt niet aanbevolen om deze verouderde manier van +fileacces nog te gebruiken. Men kan onder MSX-DOS 2 beter de +file handles gebruiken. Deze laatste kunnen ook met +directory's werken en dat kunnen FCB's niet. + + +## F O U T M E L D I N G E N + +MSX-DOS 2 kan vele foutmeldingen teruggeven. Deze hebben +alle een nummer tussen #FF en #00. De complete lijst (?) van +foutmeldingen volgt nu: + +Nummer Melding +``` +#FF Incompatible disk. +#FE Write error +#FD Disk error +#FC Not ready +#FB Verify error +#FA Data error +#F9 Sector not found +#F8 Write prtected disk +#F7 Unformatted disk +#F6 Not a DOS disk +#F5 Wrong disk +#F4 Wrong disk for file +#F3 Seek error +#F2 Bad file allocation table +#F1 - +#F0 Cannot format this drive +#EF + . + . Niet gebruikt + . +#E0 +#DF Internal error +#DE Not enough memory +#DD - +#DC Invalid MSX-DOS call +#DB Invalid drive +#DA Invalid filename +#D9 Invalid pathname +#D8 Pathname too long +#D7 File not found +#D6 Directory not found +#D5 Root directory full +#D4 Disk full +#D3 Duplicate filename +#D2 Invalid directory move +#D1 Read only file +#D0 Directory not empty +#CF Invalid attributes +#CE Invalid . or .. operation +#CD System file exists +#CC Directory exists +#CB File exists +#CA File already in use +#C9 Cannot tranfer above 64K +#C8 File alloccation error +#C7 End of file +#C6 File acces violation +#C5 Invalid process ID +#C4 No spare file handles +#C3 Invalid file handle +#C2 File handle not open +#C1 Invalid device operation +#C0 Invalid environment string +#BF Environment string too long +#BE Invalid date +#BD Invalid time +#BC RAM disk already exists +#BB RAM disk does not exist +#BA File handle has been deleted +#B9 - +#B8 Invalid sub-function number +#B7 + . + . Niet gebruikt + . +#A0 +#9F Ctrl-STOP pressed +#9E Ctrl-C pressed +#9D Disk operation aborted +#9C Error on standard output +#9B Error on standard input +#9A + . + . Niet gebruikt + . +#90 +#8F Wrong version of COMMAND +#8E Unrecognized command +#8D Command too long +#8C - +#8B Invalid parameter +#8A Too many parameters +#89 Missing parameter +#88 Invalid option +#87 Invalid number +#86 File for HELP not found +#85 Wrong version of MSX-DOS +#84 Cannot concatenate destination file +#83 Cannot create destination file +#82 File cannot be copied onto itself +#81 Cannot overwrite previous destination file +#80 + . + . Niet gebruikt + . +#00 +``` + +De hierboven met "niet gebruikt" aangegeven codes geven +meestal een system of user error xx. + +Zo dat was het voor deze keer. Allemaal een beetje saai en +droog. De volgende keer zal ik de mapper support routines en +een gedeelte van de function-calls bespreken. Ik zal er dan +enige voorbeelden bij doen zodat u niet helemaal in slaap +valt. + +Daniel Wiermans \ No newline at end of file diff --git a/sunrise_special/2/pauze_toets.md b/sunrise_special/2/pauze_toets.md new file mode 100644 index 0000000..7a71e8d --- /dev/null +++ b/sunrise_special/2/pauze_toets.md @@ -0,0 +1,258 @@ +# P A U Z E T O E T S + + +Zoals naar ik aanneem algemeen bekend is heeft de turbo R +een PAUSE toets, waarmee de computer kan worden stilgezet. +Deze PAUSE toets werkt softwarematig, en kan daardoor worden +omzeild. Dit in tegenstelling tot de PAUSE toets bij de Sony +MSX2+ computers, die hardwarematig werkt. Hierbij wordt de +computer ECHT stilgezet, waardoor er ook problemen optreden +bij externe geheugenuitbreidingen die dan geen refresh meer +krijgen. + +Deze problemen zijn er bij de turbo R niet, omdat de PAUSE +toets gewoon in de interrupt routine wordt uitgelezen. Voor +verdere uitleg over de interrupt routine verwijs ik u naar +de tekst over Interrupt Service Routines (ISR's) van Alex +van der Wal op deze Special. + + +## T U R B O R I S R + +Hieronder een disassembly van een deel van de ISR van de +turbo R. Ik zet hier alleen het deel dat voor de PAUSE toets +interessant is, voor de rest verwijs ik u dus naar de ISR +tekst van Alex. + +Bij elke interrupt springt de computer naar &H0038, waar een +JP naar de eigenlijke ISR staat: +``` +&H0038 C33C0C JP &H0C3C + +&H0C3C E5 PUSH HL +&H0C3D D5 PUSH DE +&H0C3E C5 PUSH BC +&H0C3F F5 PUSH AF +&H0C40 D9 EXX +&H0C41 08 EX AF,AF +&H0C42 E5 PUSH HL +&H0C43 D5 PUSH DE +&H0C44 C5 PUSH BC +&H0C45 F5 PUSH AF +&H0C46 FDE5 PUSH IY +&H0C48 DDE5 PUSH IX +&H0C4A CD9AFD CALL &HFD9A +&H0C4D C30B1A JP &H1A0B +&H0C50 F2020D JP P,&H0D02 +&H0C53 CD9FFD CALL &HFD9F +&H0C56 FB EI +``` +Zoals u ziet wordt er NA het aanroepen van &HFD9A naar een +routine gesprongen op adres &H1A0B: +``` +&H1A0B DB99 IN A,(&H99) ; S#0 lezen +&H1A0D A7 AND A ; vlaggen wissen +&H1A0E 08 EX AF,AF ; bewaren voor ISR +&H1A0F DBA7 IN A,(&HA7) ; PAUSE ingedrukt? +&H1A11 0F RRCA +&H1A12 3019 JR NC,&H1A2D ; nee, normale ISR +&H1A14 3AB1FC LD A,(&HFCB1) ; R800 en PAUSE led +&H1A17 F601 OR &H01 ; PAUSE led aan +&H1A19 D3A7 OUT (&HA7),A +&H1A1B 3E01 LD A,&H01 +&H1A1D D3A5 OUT (&HA5),A ; geluid uit +&H1A1F DBA7 IN A,(&HA7) ; wacht tot PAUSE +&H1A21 0F RRCA ; weer wordt +&H1A22 38FB JR C,&H1A1F ; ingedrukt +&H1A24 3AB1FC LD A,(&HFCB1) ; leds weer in +&H1A27 D3A7 OUT (&HA7),A ; oude stand +&H1A29 3E03 LD A,&H03 +&H1A2B D3A5 OUT (&HA5),A ; geluid aan +&H1A2D 08 EX AF,AF ; A=S#0 +&H1A2E C3500C JP &H0C50 ; verder met normale + ; ISR +``` +Het eerste gedeelte zit ook bij de MSX2 ISR, dit is gewoon +het uitlezen van S#0 om te kijken of het een 50/60 Hz +interrupt is of niet. De waarde van het A register wordt met +een EX AF,AF bewaard, zodat die straks weer aan de "normale +ISR" kan worden doorgegeven. + +Vervolgens wordt I/O poort &HA7 gelezen. Bit 0 van deze +poort geeft aan of PAUSE aan is of niet. Dit bit wordt gezet +zodra de PAUSE toets wordt ingedrukt, en blijft gezet totdat +de PAUSE toets nogmaals wordt ingedrukt. Is het bit 0, dan +is er geen PAUSE en wordt er verder gegaan met de normale +ISR. + +Is er wel PAUSE, dan wordt eerst het PAUSE led aangezet. Het +PAUSE led en het R800 led zitten ook op poort &HA7, en zoals +we zojuist al hebben gezien heeft poort &HA7 bij lezen een +andere functie, zodat de BIOS de status van de ledjes in het +systeem RAM bewaard (adres &HFCB1). Op de "oude" MSX +generaties met een datarecorder aansluiting was dit het +adres CASPRV, het werd gebruikt voor de datarecorder +routines. Aangezien de turbo R geen datarecorder aansluiting +meer heeft wordt dit adres nu voor dit nieuwe doel gebruikt. + +Enfin, &HFCB1 wordt gelezen en bit 0 wordt gezet (het PAUSE +led zit op bit 0, zie voor verdere uitleg over het aansturen +van de ledjes de speciale tekst daarover). Vervolgens wordt +het geluid uitgezet met een OUT (&HA5),1. Dit kun je normaal +ook gebruiken! + +Hierna wordt poort &HA7 constant uitgelezen, en gewacht +totdat de PAUSE toets weer wordt ingedrukt. Is dit gebeurt, +dan wordt eerst het led weer in de oude stand hersteld. Ik +zeg expres niet "uitgezet", omdat het PAUSE led blijft +branden als het al aanstond. Zoals u in de code kunt zien +wordt de waarde van &HFCB1 gewoon uitgelezen en naar poort +&HA7 gestuurd. + +Tot slot wordt het geluid aangezet en wordt er verder gegaan +met de normale ISR, u kunt de rest vinden in de ISR tekst. + + +## P A U S E U I T Z E T T E N + +De werking van de PAUSE toets kan op een zeer simpele manier +worden geblokkeerd: gewoon de interrupts uitzetten. Dit is +echter wel een zeer drastische oplossing, meestal heb je de +interrupts wel nodig en kan dit niet. + +Een andere methode wordt ook al in de ISR tekst aangedragen: +in de routine die je aan de hook &HFD9A hangt het +terugspringadres POPpen evenals alle registers die door de +ISR op de stack werden gezet. Ik verwijs hiervoor wederom +naar de ISR tekst. + +In machinetaal is dit een prima oplossing, in BASIC niet. +Alle dingen die normaal gesproken door de ISR worden gedaan +(toetsenbord uitlezen, ON SPRITE GOSUB, ON INTERVAL GOSUB, +ON KEY GOSUB, ON STRIG GOSUB) vinden nu niet meer plaats. +Dit geldt uiteraard ook voor de oplossing waarbij we de +interrupts helemaal uitzetten. + + +## D E O P L O S S I N G ? + +Er is nog een andere methode om dit probleem aan te pakken, +waarbij de rest van de ISR helemaal intact blijft. Het grote +nadeel is dat deze methode verre van standaard is. Ik heb de +routine op zowel FS-A1ST als FS-A1GT getest, maar het zou +heel goed kunnen dat het al niet meer werkt zodra er een +externe mapper wordt aangesloten. Het is zelfs vrijwel zeker +dat dit niet zal werken bij eventuele nieuwe MSX computers. + +Bij deze routine ga ik namelijk in de ISR in het ROM zitten +knoeien. In ROM knoeien kan toch niet, denkt u. Daar hebt u +gelijk in, maar zoals u weet heeft de turbo R de zgn. DRAM +mode, waarin RAM wordt gebruikt als ROM. In de tekst over de +R800 op Sunrise Special #1 heb ik al uitgelegd dat het +mogelijk is om bij wijze van spreken iets in de ROM te +veranderen door de ROM mode aan te schakelen, iets in het +RAM te veranderen dat voor DRAM wordt gebruikt, en +vervolgens weer de DRAM mode aan te schakelen. Deze methode +werkt dus alleen in samenwerking met de DRAM mode. + + +## I N D E I S R K N O E I E N + +We hoeven maar twee bytes in de ISR te veranderen om te +zorgen dat hij de PAUSE toets niet meer kan detecteren. Als +u nog even "terugbladert" kunt u zien dat er op adres &H1A0F +een IN A,(&HA7) instructie staat (opcode DB A7). We +veranderen dit gewoon in LD A,0 (opcode 3E 00), en de ISR +zal het niet meer merken als de PAUSE toets wordt ingedrukt. + +Dit wordt gedaan door "PAUSEOFF.BIN", een ML routine die op +deze diskette staat. De source staat er ook op, +"PAUSEOFF.ASC". Hier volgt deze source, voorzien van extra +commentaar. + +``` +; P A U S E O F F . A S C +; Alleen turbo R, zet PAUSE toets uit +; Door Stefan Boer, (c) Ectry 1992 +; Sunrise Special #2, (c) Sunrise 1992 + + ORG &HD000 + + LD A,&H81 + CALL &H0180 ; R800 ROM mode + IN A,(&HFE) + PUSH AF ; bewaar oude &HFE page + LD A,&HFC + OUT (&HFE),A ; DRAM page met MAIN ROM +``` + +Als de computer opstart worden de 32 kB MAIN ROM, de 16 kB +SUB ROM en de 16 kB Kanji ROM naar de bovenste 64 kB RAM +gekopieerd. Dit RAM wordt als DRAM gebruikt indien de R800 +DRAM mode wordt aangeschakeld. Hierbij komt de onderste 16 +kB van het MAIN ROM (waar wij in willen gaan knoeien) in +mapper page &HFC terecht. (Zie de R800 tekst op Sunrise +Special #1.) Wij zetten dit RAM op &H8000 met OUT +(&HFE),&HFC. + +``` + LD HL,(&H9A0F) ; &H1A0F+&H8000 + LD DE,&HA7DB ; DB A7 = IN A,(&HA7) + RST &H20 ; controle + JP NZ,ERROR ; foutmelding als niet Ok +``` + +Hier wordt gecontroleerd of op adres &H1A0F (dit wordt +&H9A0F omdat het op &H8000 staat) wel een IN A,(&HA7) staat. +Dit als een beperkte controle, op deze manier merk je het +bijvoorbeeld als het DRAM is gewist. + +``` + LD HL,&H3E ; 3E 00 = LD A,0 + LD (&H9A0F),HL ; knoeien + POP AF + OUT (&HFE),A ; &HFE page herstellen + LD A,&H82 + CALL &H0180 ; R800 DRAM mode + LD HL,TEKST + CALL PRTXT + RET +``` + +Hier wordt het "patchen" gedaan, en wordt de oude &HFE page +weer hersteld. Tot slot wordt de DRAM mode aangeschakeld en +melden we met een tekstje op het scherm dat de PAUSE toets +nu uit staat. + +``` +ERROR: LD HL,ERRTXT + CALL PRTXT + POP AF + OUT (&HFE),A + RET + +PRTXT: LD A,(HL) + AND A + RET Z + CALL &HA2 + INC HL + JP PRTXT + +TEKST: DM 13,10,"PAUSE inhibited",13,10 + DM "(c) Ectry 1992",13,10,10,0 + +ERRTXT: DB 13,10,7,"No correct DRAM found",13,10,0 +``` + +## T E N S L O T T E + +Nogmaals, dit is zeker geen standaardroutine! Maar hij zal +normaal gesproken wel werken en het voorkomt ongewenst +gebruik van de PAUSE toets, terwijl de ISR verder gewoon +zijn werk blijft doen. + +In machinetaal kun je veel beter de "POPjes aan &HFD9A +hangen" methode gebruiken, dat werkt altijd en kapt de (toch +onnodige) ISR af. + +Stefan Boer diff --git a/sunrise_special/2/pcm_routines_van_de_bios.md b/sunrise_special/2/pcm_routines_van_de_bios.md new file mode 100644 index 0000000..b5109a2 --- /dev/null +++ b/sunrise_special/2/pcm_routines_van_de_bios.md @@ -0,0 +1,84 @@ +# P C M - R O U T I N E S V A N D E B I O S + + +Vertaling van een gedeelte van het artikel over de turbo R +uit het Japanse MSX-Magazine: + + +## P C M P L Y +``` +Funktie : PCM-weergave +Adres : Main ROM #0186 +In : A + Bit 7 6 5 4 3 2 1 0 + | | | | | `-`---> frequentie + | `-------------> 0 + `---------------> VRAM/MRAM + EHL (adres van de data) + DBC (lengte van de data) +Terug : carry flag + 0 normale beeindiging + 1 abnormale beeindiging + | + `--> A (reden van de abnormale beeindiging) + 1 fout bij het instellen van de frequentie + 2 onderbreking veroorzaakt door de STOP + toets + EHL (adres waar de onderbreking plaatsvond) +Verandert : alle registers +``` + +De PCM-geluidsdata worden als bit 7 van register A ��n is +uit het video-RAM gehaald en als het nul is uit het main RAM +gehaald. Bovendien hebben de waarden van het D- en +E-register slechts een betekenis in het geval dat de data +zich in het video-RAM bevindt. +D.m.v. bit 1 en bit 0 van de accumulator stelt men de +sample-frequentie in. Maar, pas op: 15.75 kilohertz is +alleen mogelijk wanneer de turbo R in de R800-DRAM-mode +staat: + +``` +00 W> 15.75 kilohertz +01 W> 7.875 kilohertz +10 W> 5.25 kilohertz +11 W> 3.9375 kilohertz +``` + +## P C M R E C +``` +Functie : PCM-opname +Adres : Main ROM #0189 +In : A + Bit 7 6 5 4 3 2 1 0 + | | | | | | `-`-> frequentie + | | | | | `-----> compressie + | `-`-`-`-------> trigger + `---------------> VRAM/MRAM + + EHL (adres van de data) + DBC (lengte van de data) +Terug : carry flag + 0 normale be�indiging + 1 abnormale be�indiging + | + `--> A (reden van de abnormale be�indiging) + 1 fout bij het instellen van de frequentie + 2 onderbreking veroorzaakt door de STOP + toets + EHL (adres waar de onderbreking plaatsvond) +Verandert : alle registers +``` +De codering van ingave bij bit 7, 1 en 0 van het A register +is hetzelfde als bij PCMPLY. Bit 6 t/m bit 3 van het A +register heten 'trigger' en duiden de sterkte van het geluid +aan, waarbij het zover komt dat de opname begint. Als deze +waarde nul is, wordt de opname onmiddellijk gestart. + +Verder worden, als bit 2 van register A ��n is, de +opname-data gecomprimeerd. Als het nul is, worden ze niet +gecomprimeerd. +Het comprimeren houdt in dat, als de input 0 is, het wordt +vervangen door een code. Dit kan heel veel bytes schelen. + +Bernard Lamers \ No newline at end of file diff --git a/sunrise_special/2/pcm_sampler.md b/sunrise_special/2/pcm_sampler.md new file mode 100644 index 0000000..8133640 --- /dev/null +++ b/sunrise_special/2/pcm_sampler.md @@ -0,0 +1,760 @@ +# P C M S A M P L E R + +Een van de leuke dingen van de turbo R is de ingebouwde PCM +sampler. Voor het opnemen en afspelen met deze PCM chip zijn +twee nieuwe BIOS calls aanwezig, die we in dit artikel +zullen gaan bespreken. + +Bovendien zal het programma LONG PCM worden besproken, +waarmee je zeer lange samples kunt opnemen en afspelen. De +lengte van deze samples is het RAM geheugen plus 32 kB, op +een standaard FS-A1ST is dit dus 288 kB en op een standaard +FS-A1GT 544 kB. Dit programma maakt gebruik van de BIOS +calls. + +De volgende keer zal ik uitleggen hoe je de PCM chip +rechtstreeks kunt aansturen. Hiervoor wordt onder andere de +systeem counter van de turbo R gebruikt, die dan ook zal +worden besproken. + +Maar nu eerst de twee nieuwe BIOS calls. + + +## N I E U W E B I O S C A L L S +``` +Naam: PCMPLY +Adres: &H0186 (MAIN ROM) +Functie: sample afspelen +Invoer: EHL = startadres + DBC = lengte + A = mode + bit 0 en 1: 00 15.75 kHz + 01 7.875 kHz + 10 5.25 kHz + 11 3.9375 kHz + bit 2-6: 0 + bit 7: 0 RAM + 1 VRAM +``` +Bij gebruik van alleen RAM zou een 16 bits adres voldoende +zijn, maar omdat we ook met VRAM kunnen werken zijn 17 bits +noodzakelijk. Daar wordt het DE register voor gebruikt, het +17de bit van het startadres staat in E en het 17de bit van +de lengte staat in D. Voor de duidelijkheid een paar +voorbeelden: + +1) Sample op adres &H9000-&HBFFF (RAM) afspelen op 5.25 kHz: +``` + LD HL,&H9000 + LD BC,&H3000 ; &HBFFF-&H9000+1 = &H3000 + LD DE,0 + LD A,&B00000010 + CALL PCMPLY +``` +2) Sample op adres &H04000-&H1BFFF (VRAM) afspelen op 15.75 + kHz: +``` + LD HL,&H4000 + LD BC,&H8000 ; &H1BFFF-&H04000+1 = &H18000 + LD DE,&H0100 + LD A,&B10000000 + CALL PCMPLY +``` +``` +Naam: PCMREC +Adres: &H0189 (MAIN ROM) +Functie: sample opnemen +Invoer: EHL = startadres + DBC = lengte + A = mode + bit 0 en 1: zie PCMPLY + bit 2 : 0 crunch mode uit + 1 crunch mode uit + bit 3-6 : trigger + bit 7 : zie PCMPLY +``` +Voor de uitleg bij EHL en DBC verwijs ik naar PCMPLY. Voor +bit 2 heb ik zelf maar de naam "crunch mode" verzonnen, ik +weet niet wat de offici�le naam hiervoor is. Als dit bit is +gezet neemt "stilte" veel minder geheugenruimte in beslag. +Een extra voordeel is dat je geen ruis hoort bij een +"stilte". Deze mode wordt bijvoorbeeld gebruikt bij zowel +het ingebouwde programma van de turbo R als bij de +meegeleverde sample tool. Je kunt duidelijk merken dat het +geheugen veel minder snel vol is als er weinig geluid is. + +De trigger kennen we al van de MSX-AUDIO sampler. Als PCMREC +wordt aangeroepen wordt gewacht met opnemen totdat er een +signaal binnenkomt dat de triggerwaarde evenaart. Als er 0 +wordt ingevuld voor de trigger wordt de opname meteen +gestart. Ook hier weer twee voorbeelden: + +1) Sample met 7.875 kHz opnemen van &H8300 tot &HD4FF (RAM), + trigger is uit en crunch mode is aan: +``` + LD HL,&H8300 + LD BC,&H5200 ; &H8300-&HD4FF+1 = &H5200 + LD DE,0 + LD A,&B00000101 + CALL PCMREC +``` +2) Sample met 3.9375 kHz opnemen van &H13000 tot &H13FFF + (VRAM), trigger is 10 en crunch mode is uit: +``` + LD HL,&H3000 + LD BC,&H1000 ; &H13000-&H13FFF+1 = &H1000 + LD DE,&H0001 + LD A,&B11010011 + CALL PCMREC +``` + +Het is nu tijd voor het voorbeeldprogramma: LONG PCM. Dit +programma is vanzelfsprekend ook onder dezelfde naam in het +softwaremenu te vinden en zoals u van mij gewend bent staat +de assemblerlisting in ASCII formaat op de disk onder de +naam "LONGPCM.ASC". We gaan deze source nu bespreken. + +(Ik denk dat het wel verstandig is om het programma eerst +eens uit te proberen, en dan pas de assemblerlisting te +bestuderen.) + +``` +; L O N G P C M . A S M +; Door Stefan Boer 25/10/92 +; Lange samples opnemen en afspelen +; Gebruikt 120 kB VRAM en RAM - 80 kB (voor DRAM en +; systeem RAM + routine) +; Alleen MSX turbo R +; Geen DOS2!! +``` + +Om het simpel te houden wordt DOS2 niet ondersteund, het +aansturen van het geheugen zou dan namelijk anders worden. +Bovendien moet er dan rekening worden gehouden met de 32 kB +RAM die DOS2 in beslag neemt, en dat doen we ook niet. + +``` +CHGMOD: EQU &H5F +ERAFNK: EQU &HCC +CHGET: EQU &H9F +CHPUT: EQU &HA2 +CHGCPU: EQU &H0180 +PCMREC: EQU &H0189 +PCMPLY: EQU &H0186 +LINL80: EQU &HF3AE +``` + +De in de routine gebruikte BIOS calls en systeem RAM +adressen worden hier gedefinieerd. + +``` + ORG &HC800 + IN A,(&HFE) + PUSH AF + LD A,&H82 + CALL CHGCPU ; R800 DRAM mode + CALL ERAFNK ; KEY OFF + LD A,80 + LD (LINL80),A ; WIDTH 80 + XOR A + CALL CHGMOD ; SCREEN 0 + DI + LD A,&HF1 ; COLOR 15,1,1 + OUT (&H99),A + LD A,7+128 + OUT (&H99),A + EI +``` + +Hier wordt eerst de inhoud van I/O poort &HFE bewaard, zodat +we die straks weer kunnen herstellen. Verder wordt de +computer in R800 DRAM mode gezet, en initialiseren we het +scherm. De R800 DRAM mode is noodzakelijk omdat anders +PCMREC alleen werkt bij lage frequenties. + +``` + CALL MEMCNT ; geheugen tellen + LD (MAXPGE),A +MAIN: LD HL,WELKOM + CALL PRINTS + LD A,(MAXPGE) + LD B,16 + DEFB &HED,&B11000001 ; MULUB A,B (HL=16*A) + LD BC,112 + ADD HL,BC ; VRAM erbij + CALL PRTDEC ; getal in decimaal naar scherm +``` + +Hier wordt eerste MEMCOUNT aangeroepen, mijn standaard- +routine om de grootte van de actuele memory mapper te +bepalen die we op Sunrise Special #1 al hebben behandeld. Ik +maak er hier dus verder geen woorden aan vuil. Deze routine +geeft in het A register de hoogste mapper pagina terug. Bij +256 kB is dit bijvoorbeeld 15. Deze waarde wordt opgeslagen. +Vervolgens worden de titel e.d. op het scherm gezet, de +routine PRINTS drukt een string af die op adres HL begint en +eindigt met een 0. + +Vervolgens wordt de hoeveelheid samplegeheugen berekend. +MEMCNT telt automatisch het RAM dat voor DRAM wordt gebruikt +al niet mee, op een turbo R met 256 kB is (MAXPGE) dus +gelijk aan 15-4 = 11. Er zijn dus 12 mapperpagina's, waarvan +er een (nr. 0) nodig is voor het systeem RAM en het +programma (die mapper pagina staat dus op &HC000). (MAXPGE) +geeft dus zonder verdere correctie het aantal memory mapper +pagina's (van 16 kB) dat voor samples vrij is. + +Dit vermenigvuldigen we via MULUB met 16, het antwoord komt +in HL. Vervolgens tellen we er nog 112 bij op, omdat we de +onderste 16 kB van het 128 kB grote VRAM niet gebruiken. +Deze waarde wordt met PRTDEC in decimaal naar het scherm +gestuurd (met voorloopnullen), deze standaardroutine zal ik +een andere keer nog wel eens bespreken. + +``` + LD HL,WELKM2 + CALL PRINTS + LD HL,MENU + CALL PRINTS +``` + +Met WELKM2 wordt er nog een "kB" achter het zojuist geprinte +getal gezet, achter MENU gaat het complete menu schuil. (Het +is misschien handig om even vooruit te kijken naar de +definites van WELKOM, WELKM2, MENU, etc.) + +``` + LD A,(FREQUE) ; current frequency + LD HL,FREQ0 + AND A + JR Z,FQ0 + LD HL,FREQ1 +FQ0: CALL PRINTS +``` + +Hier wordt de actuele frequentie (15.75 kHz of 7.875 kHz) op +het scherm gezet. Vanaf FREQ0 en FREQ1 staan de juiste +teksten, via een voorwaardelijke sprong wordt HL met de +juiste waarde geladen. Vervolgens wordt de juiste string +op het scherm gezet. + +``` + LD HL,MENU2 + CALL PRINTS + LD A,(CRUNCH) ; crunch mode + LD HL,CRU0 + AND A + JR Z,CR0 + LD HL,CRU1 +CR0: CALL PRINTS +``` + +Hier hetzelfde, alleen nu voor de crunch mode. + +``` + LD HL,MENU3 ; trigger + CALL PRINTS + LD A,(TRIGGR) + LD L,A + LD H,0 + CALL PRTDC2 +``` + +Bij de trigger gaat het om een getal. Dit wordt in HL gezet +en vervolgens wordt PRTDC2 aangeroepen, een ingekorte versie +van PRTDEC die een decimaal getal op twee cijfers print +(eventueel met voorloopnul). + +``` + LD HL,MENU4 + CALL PRINTS + LD A,(LIST_F) + OUT (&HA5),A ; listen aan/uit + LD HL,CRU0 + AND A + JR Z,LI0 + LD HL,CRU1 +LI0: CALL PRINTS ; listen +``` + +Tot slot van ons overzicht van de instellingen de instelling +"listen". Hiermee kan het binnenkomende signaal worden +beluisterd, handig om het volume af te stellen. Let op: zet +dit alleen aan als er een extrne geluidsbron (bv. CD speler) +of microfoon op de externe microfoonaansluiting op de +achterzijde is aangesloten, anders gaat het geluid zingen +wat een afschuwelijke herrie tot resultaat heeft! + +Het doorvoeren van het binnenkomende signaal naar de +luidspreker gaat met een OUT &HA5,10, u kunt dit ook in +BASIC gebruiken! Met een OUT &HA5,0 wordt het weer uitgezet. +De waarde wordt elke keer opnieuw naar I/O poort &HA5 +gestuurd, omdat het wordt uitgezet bij aanroep van PCMPLY of +PCMREC. + +``` + LD HL,PROMPT + CALL PRINTS +GETKEY: CALL CHGET + CP "1" + JR C,GETKEY + CP "7"+1 + JR NC,GETKEY ; controle tussen 1 en 7 + PUSH AF + CALL &HA2 + LD A,13 + CALL &HA2 + LD A,10 + CALL &HA2 +``` + +Hier wordt de prompt ("Your choice please?") op het scherm +gezet. Vervolgens wordt CHGET aangeroepen, die op een toets +wacht en de ASCII van die toets in A teruggeeft. We kijken +met voorwaardelijke sprongen of het een toets tussen 1 en 7 +is. De carry wordt bij CP "1" gezet als A kleiner is dan +&H31, de ASCII van "1". Bij een carry wordt het dus nog eens +geprobeerd. Bij de tweede CP wordt er vergeleken met "7"+1, +als A inderdaad kleiner of gelijk is aan 7 wordt de carry +niet gezet. Anders moeten we het nog eens proberen. Bij een +goede toets wordt AF bewaard en wordt er een linefeed +(13,10) gegeven. + +``` + POP AF + SUB "1" ; omzetten in getal 0-7 + ADD A,A + LD E,A + LD D,0 + LD HL,JPTAB + ADD HL,DE ; bereken adres in sprongtabel + LD E,(HL) + INC HL + LD D,(HL) + EX DE,HL + JP (HL) ; spring naar juiste routine +``` + +Hier wordt er aan de hand van het ingetoetse cijfer naar de +juiste routine gesprongen. Eerst halen we de eerder bewaarde +waarde van A terug met een POP. Vervolgens trekken we er de +ASCII van "1" vanaf, zodat we een getal tussen 0 en 6. Met +ADD A,A wordt dit met twee vermenigvuldigd, omdat een +sprongadres twee bytes in beslag neemt. Deze waarde wordt in +DE gezet en vervolgens bij het beginadres van de tabel met +sprongadressen (dat in HL staat) opgeteld. Het adres dat +hier staat wordt in DE gezet, en daarna met een EX DE,HL aan +HL overgedragen. De JP (HL) springt tenslotte naar het +juiste adres. Onthoud deze constructie goed, het is de beste +manier om een dergelijk menu te programmeren. + +Nu komen de afzonderlijke routines, die door het maken van +een keuze uit het menu worden aangeroepen. De routines +eindigen met een JP MAIN, waardoor het scherm wordt gewist +en het menu opnieuw opgebouwd. Vervolgens kan de gebruiker +zijn (of haar?) volgende keuze maken. + +``` +; 1) Record sample + +RECORD: LD HL,RECTXT + CALL PRINTS + CALL CHGET + LD HL,RECTX2 + CALL PRINTS +``` + +Eerst wordt er gevraagd om op een toets te drukken om met +het opnemen te beginnen. Vervolgens wordt de tekst +"Recording..." op het scherm gezet. + +``` + LD A,(TRIGGR) + ADD A,A + ADD A,A + ADD A,A ; * 8 ==> naar bit 3-6 + OR 128 ; VRAM + LD C,A + LD A,(FREQUE) + AND A + JR Z,CRNCH ; 15.75 kHz + SET 0,C ; 7.875 kHz +CRNCH: LD A,(CRUNCH) + AND A + JR Z,REC ; crunch mode uit + SET 2,C ; crunch mode aan +REC: LD A,C + PUSH AF +``` +Eerst samplen we het VRAM vol. Hier wordt de juiste waarde +voor het A register berekend. De trigger wordt met drie ADD +A,A instrukties naar bit 3-6 verplaatst. Met een OR 128 +wordt het VRAM bit gezet. Tot slot worden nog de juiste +crunch en frequntie bits toegevoegd. + +``` + LD HL,&H4000 ; startadres in VRAM = &H04000 + LD BC,&HC000 ; lengte in VRAM = &H1C000 + LD DE,&H0100 + CALL PCMREC +``` + +Het eigenlijke aanroepen van de BIOS routine wordt hier +gedaan. De eerste 16 kB VRAM wordt overgeslagen, hier staat +immmers de schermdata. + +``` + POP AF + AND &B00000111 ; wis VRAM en trigger + LD (PARAM),A +``` + +We hadden de berekende waarde voor A zojuist bewaard, zodat +we die niet nog een keer hoeven te berekenen. De trigger +moet nu echter worden uitgezet, omdat er anders een "gat" in +de opnamen komt bij de overgang van VRAM naar RAM. Uiteraard +wordt ook bit 7 (het VRAM bit) gewist. + +``` + LD A,(MAXPGE) + LD B,A +RECLUS: LD A,B + OUT (&HFE),A + PUSH BC + LD HL,&H8000 + LD BC,&H4000 + LD DE,0 + LD A,(PARAM) + CALL PCMREC + POP BC + DJNZ RECLUS + JP MAIN +``` + +Nu is het RAM aan de beurt. Bovenstaande lus wordt voor alle +mapper pagina's die beschikbaar zijn voor samplen doorlopen. +De juiste waarde wordt naar I/O poort &HFE gestuurd, +vervolgens wordt PCMREC met de juiste parameters +aangeroepen. + +``` +; 2) Play sample + +PLAY: LD HL,PLYTXT + CALL PRINTS + LD A,(FREQUE) + OR 128 ; VRAM + LD HL,&H4000 + LD BC,&HC000 + LD DE,&H0100 + CALL PCMPLY +``` + +Eerst worde tekst "Playing..." op het scherm gezet. +Vervolgens wordt de waarde voor het A register berekend. Bij +afspelen is dit veel simpeler dan bij opnemen, het gaat +immers alleen om de frequentie en het RAM/VRAM bit. +Vervolgens wordt de sample in het VRAM afgespeeld. + +``` + LD A,(MAXPGE) + LD B,A +PLYLUS: LD A,B + OUT (&HFE),A + PUSH BC + LD HL,&H8000 + LD BC,&H4000 + LD DE,0 + LD A,(FREQUE) + CALL PCMPLY + POP BC + DJNZ PLYLUS + JP MAIN +``` + +Deze lus lijkt sprekend op die voor het opnemen, verdere +uitleg is hier dan ook overbodig. Merk op dat het A register +nu alleen de frequentie bits bevat, het RAM/VRAM bit is +immers 0. + +``` +; 3) Frequency 15.75 kHz/7.875 kHz + +CHFREQ: LD A,(FREQUE) + XOR 1 + LD (FREQUE),A + JP MAIN +``` + +Hier wordt er geswitchd tussen 15.75 en 7.875 kHz. De +frequentie wordt aangegeven door bit 0 van (FREQUE), dit bit +wordt met een XOR 1 omgeklapt. Door de JP MAIN wordt de +wijziging vanzelf op het scherm zichtbaar gemaakt. + +``` +; 4) Crunch mode ON/OFF + +CHCRUN: LD A,(CRUNCH) + XOR 1 + LD (CRUNCH),A + JP MAIN +``` + +Analoog aan de frequentie. De trigger is echter wat +moeilijker, omdat hier een getal tussen 0 en 15 moet worden +ingesteld. We zetten daarom eerst een tekstje op het +scherm. Vervolgens wordt de tekst "Trigger: " op het scherm +gezet met daarachter de actuele waarde. Hiervoor gebruiken +we PRTDC2. + +``` +; 5) Change trigger + +CHTRIG: LD HL,TRGTXT + CALL PRINTS +CHTRG2: LD HL,TRGTX2 + CALL PRINTS + LD A,(TRIGGR) + LD L,A + LD H,0 + CALL PRTDC2 +CURSOR: CALL CHGET + CP " " ; spatie + JP Z,MAIN + CP 30 ; cursor omhoog + JR Z,TRGUP + CP 31 ; cursor omlaag + JR NZ,CURSOR + LD A,(TRIGGR) + AND A + JR Z,CURSOR + DEC A + LD (TRIGGR),A + JR CHTRG2 +``` + +Bij CURSOR wordt er op een toets gewacht. Is dit een spatie, +dan is de juiste waarde blijkbaar bereikt en kan worden +teruggekeerd naar het hoofdmenu. Voor cursor omhoog wordt +naar de juiste routine gesprongen. Is het ook niet cursor +omlaag, dan moet de gebruiker het nog maar eens met een +andere toets proberen (we springen terug naar cursor). +Cursor omlaag was nu dus ingedrukt, en dus controleren we +eerst met een AND A of A niet toevallig gelijk is aan 0, +want dan valt er niets te verlagen. Is dit niet het geval, +dan wordt A met een verlaagd en wordt de nieuwe trigger +waarde opgeslagen. Door naar CHTRG2 te springen wordt de +nieuwe waarde op het scherm gezet. + +``` +TRGUP: LD A,(TRIGGR) + CP 15 + JR Z,CURSOR + INC A + LD (TRIGGR),A + JR CHTRG2 +``` + +De routine voor trigger up is praktisch gelijk aan die voor +trigger down. Listen gaat weer net als frequentie en crunch, +met het verschil dat er hier wordt geswitchd tussen 10 en 0. +De OUT (&HA5),A is eigenlijk overbodig, dit wordt immers in +MAIN al gedaan. + +``` +; 6) Listen ON/OFF + +LISTEN: LD A,(LIST_F) + XOR 10 + LD (LIST_F),A + OUT (&HA5),A + JP MAIN + +; 7) Quit + +QUIT: LD HL,QUITTX + CALL PRINTS + POP AF + OUT (&HFE),A + RET +``` + +Bij het verlaten van het programma wordt er een +afscheidstekst op het scherm gezet. Vervolgens wordt de +inhoud van I/O poort &HFE hersteld en wordt er teruggekeerd +naar BASIC. + +``` +PRINTS: LD A,(HL) + AND A + RET Z + CALL CHPUT + INC HL + JR PRINTS +``` + +Deze standaardroutine zet een string op het scherm. HL wijst +naar het eerste teken van de string, de string moet zijn +afgesloten met een 0. Dit is een van de bekendste +standaardroutines. + +``` +MAXPGE: DS 1 +PARAM: DS 1 +FREQUE: DB 0 +TRIGGR: DB 0 +CRUNCH: DB 0 +LIST_F: DB 0 +JPTAB: DW RECORD,PLAY,CHFREQ,CHCRUN,CHTRIG,LISTEN,QUIT +``` + +Hierboven het numerieke datagebied. Hier worden de +variabelen opgeslagen, bovendien staat hier de sprongtabel +voor het menu. Hieronder volgt de tekstdata, alle strings +die in het programma met PRINTS op het scherm kunnen worden +gezet. (Nvdr. Omdat de layout van de Special in 60 kolommen +is, past het hier en daar niet echt lekker.) + +``` +WELKOM: DM 12,"LONG PCM v1.0 " + DM " By Stefan Boer 25/10/92" + ,13,10 + DM "MSX turbo R only, no MSX-DOS 2 allowed!" + ,13,10 + DM "Uses 112 kB VRAM and all your available RAM" + ,13,10,10 + DM "Total available memory: ",0 +WELKM2: DM " kB",13,10,13,10,0 +MENU: DM "1) Record sample",13,10 + DM "2) Play sample",13,10 + DM "3) Frequency 15.75 kHz/7.875 kHz",13,10 + DM "4) Crunch mode ON/OFF",13,10 + DM "5) Change trigger",13,10 + DM "6) Listen ON/OFF",13,10 + DM "7) Quit",13,10,10 + DM "Current frequency: ",0 +FREQ0: DM "15.75 kHz",13,10,0 +FREQ1: DM "7.875 kHz",13,10,0 +MENU2: DM "Crunch mode : O",0 +CRU0: DM "FF",13,10,0 +CRU1: DM "N",13,10,0 +MENU3: DM "Trigger : ",0 +MENU4: DM 13,10,"Listen : O",0 +PROMPT: DM 13,10,"Your choice please? ",0 +TRGTXT: DM 13,10,"Use cursor keys up and down, space bar + when ready",13,10,0 +TRGTX2: DM 13,"Trigger: ",0 +QUITTX: DM 13,10,"Good bye!",13,10,0 +RECTXT: DM 13,10,"Press any key to start recording",0 +RECTX2: DM 13,10,"Recording...",0 +PLYTXT: DM 13,10,"Playing...",0 +``` + +Onderstaande standaardroutine zet het getal in HL op het +scherm, met voorloopnullen. Deze routine wordt een andere +keer misschien nog eens behandeld. + +``` +; PRTDEC +; Zet getal in HL in decimaal op scherm +; Door Stefan Boer, juli 1992 + +PRTDEC: LD DE,1000 ; 0-9999 + CALL PRINT + LD DE,100 + CALL PRINT +PRTDC2: LD DE,10 ; 0-99 + CALL PRINT + LD DE,1 + CALL PRINT + RET + +PRINT: XOR A ; A=0 +NEXT: LD B,H + LD C,L ; LD BC,HL + OR A ; wis carry, A blijft gelijk + SBC HL,DE + JP C,EINDE + INC A + JP NEXT +EINDE: LD H,B + LD L,C ; LD HL,BC + ADD "0" + CALL CHPUT ; cijfer naar scherm + RET +``` + +De volgende standaardroutine is al op de vorige Sunrise +Special besproken, voor uitleg verwijs ik je dus naar die +Special. + +``` +; MEMCNT +; Door Stefan Boer 19/03/92 +; Uitvoer: A=aantal vrije memory mapper segmenten van 16 kB + +ADRES: EQU &H81FF +MEMPRT: EQU &HFE + +MEMCNT: LD HL,ADRES + LD DE,BUFFER + LD C,MEMPRT + IN A,(C) + PUSH AF + LD B,0 +SAVE: OUT (C),B + LD A,(HL) + LD (DE),A + INC DE + DJNZ SAVE + LD B,0 + XOR A +ZERO: OUT (C),B + LD (HL),A + DJNZ ZERO + LD D,0 + LD B,0 +CHECK: OUT (C),B + LD A,(HL) + CP &HFF + JR Z,SLAOVR + INC D + LD (HL),&HFF +SLAOVR: DJNZ CHECK + PUSH DE + LD DE,BUFFER + LD B,0 +RESTOR: OUT (C),B + LD A,(DE) + LD (HL),A + INC DE + DJNZ RESTOR + POP DE + POP AF + OUT (C),A + LD A,D + DEC A + RET + +BUFFER: DEFS 256 +``` + +## T O T S L O T + +In het softwaremenu vindt u het programmaatje LONGPCM.BAS, +dat de routine van disk laadt en start. Bovendien zorgt het +voor de terugkeer naar het softwaremenu. + +Ik wil er nog even op wijzen dat ik dit programma vooral heb +geschreven om de leerzaamheid, en niet om het nut. In de +routine komen behalve het samplen ook andere dingen voor, +zoals het maken van een menu. Het ging mij er uiteindelijk +om om te laten zien hoe de BIOS routines PCMREC en PCMPLY in +de praktijk kunnen worden gebruikt. + +De volgende keer zal ik zoals beloofd het direct aansturen +van de samplechip bespreken, de frequentie kan dan +bijvoorbeeld veel nauwkeuriger worden gekozen. Maar daarover +de volgende keer meer. + +Stefan Boer \ No newline at end of file diff --git a/sunrise_special/2/programmeer_taal_c.md b/sunrise_special/2/programmeer_taal_c.md new file mode 100644 index 0000000..b95b8f6 --- /dev/null +++ b/sunrise_special/2/programmeer_taal_c.md @@ -0,0 +1,587 @@ +# D E P R O G R A M M E E R T A A L C ( 1 ) + + + +## O V E R D E Z E C U R S U S + +Deze cursus is bedoeld voor MSX'ers die nader willen +kennismaken met de programmeertaal C. Enige +programmeerkennis in BASIC of PASCAL kan nuttig zijn, +aangezien de overeenkomsten en verschillen tussen C en de +andere twee talen uitgebreid aan bod zullen komen. Tevens +hoop ik dat het aantal C-programmeurs door dit initiatief +nogal zal stijgen, zodat een gezonde uitwisseling kan +ontstaan van ide�en, technieken, routines of zelfs hele +bibliotheken. + + +## D E C - C O M P I L E R S V O O R M S X + +Natuurlijk is het nuttig om een C-compiler te bezitten, om +de programmeervoorbeelden zelf te kunnen compileren. Bij +mijn weten zijn de volgende C-compilers voor MSX +beschikbaar: + ++ HiSoft C++ CP/M produkt, is echter in een voor MSX + aangepaste vorm beschikbaar. Geen PD, maar + toch ruim in BBS'en te downloaden. Overigens, + C++ is niet de C++ zoals het ANSI-comitee de + object-oriented versie van C gedoopt heeft. + Kent geen float's en long's. + ++ ASCII-C Speciaal voor MSX. Wat bewerkelijker in het + gebruik dan C++, maar levert zeer efficiente + code op, en stimuleert bovendien modulair + programmeren. Verder zeer flexibel. Kent geen + float's en long's. Ook geen PD, maar eveneens + goed verspreid onder de MSX'ers. Werkt + voortreffelijk samen met assembler. + ++ SMALL C CP/M produkt. Een Public Domain C, + oorspronkelijk gepubliceerd in Dr. Dobbs. Er + zijn vele varianten van in omloop. (Nvdr: + Natuurlijk omdat de source wordt + meegeleverd!) Levert helaas weinig efficiente + of compacte code, en kent in vergelijking met + de voorgaande twee compilers de meeste + beperkingen, met name de datastructuren zijn + zeer beperkt. Is daardoor niet echt geschikt + voor wat grotere programma's. + + GST-C Speciaal voor MSX. Lijkt van SMALL-C te zijn + afgeleid en kent ongeveer dezelfde + beperkingen. Geen PD. + + BDS-C CP/M produkt. Een wat oudere compiler, die + wel echter het volledigst de C-standaard + lijkt te volgen. Verder bij mij weinig van + bekend. + +Verder zijn andere C-compilers voor CP/M ook te gebruiken, +zoals AZTEC-C, MIX-C, enzovoort. + +De met een + gemerkte compilers heb ik zelf. Wellicht dat er +nog mensen zijn die een van de andere C-compilers in hun +bezit hebben, of compilers die zelfs niet in het lijstje +staan: in dat geval zou ik die graag eens ontvangen, om een +vergelijkend onderzoekje te doen. (Snelheid, grootte van +programma's, volledigheid). + + +## G E B R U I K V A N C - C O M P I L E R S + +C-compilers zijn wat omslachtiger in het gebruik dan BASIC, +of Turbo PASCAL (bij kleine programma's, tenminste). Om een +programma te compileren zijn de volgende stappen +noodzakelijk: + + + Editen van het ASCII-file met de programmatekst + (+ Pre-compileren) + + Compileren + (+ Assembleren) + (+ Optimaliseren) + (+ Linken) + +De stappen tussen haakjes zijn niet altijd noodzakelijk. +ASCII-C heeft vier van de vijf stappen nodig (alleen +optimaliseren niet), HiSoft C++ darentegen maar twee. De +meeste compilers zitten tussen deze twee uitersten in. + +Na de laatste stap hebben we als alles goed ging een +.COM-file gecre�erd, wat direkt onder MSX-DOS kan worden +uitgevoerd. Als het werkt: prima! Maar werkt het niet: "back +to the drawing-board". + + +## I N L E I D I N G + +In de loop der tijden hebben computerdeskundigen heel wat +manieren gevonden om computers te programmeren. De oudste en +primitiefste manier was programmeren in machinetaal door het +leggen van draadverbindingen! Onnodig te zeggen dat zoiets +alleen gaat bij de allerkleinste prorammaatjes. Ook uit die +tijd stamt de term "bug" (= fout in het programma), omdat +insekten toen daadwerkelijk voor sluitingen - en dus +veranderingen in het programma - in de grote panelen konden +zorgen. In die tijd was programmeren dan ook voorbehouden +aan de experts. + +Deze manier van programmeren moest gelukkig al snel het veld +ruimen voor wat geavanceerdere methodes: de assembler was +geboren, en programmeren werd al een heel stuk genoeglijker. +Toch bleven er problemen. In die tijd volgde het ene model +computer het andere snel op, en ieder nieuw model had weer +een wat andere machinetaal, en dus moesten de programma's +iedere keer door programmeurs vertaald worden. Duur en +omslachtig. + +Dus deden de eerste hogere programmeertalen hun intrede: +COBOL (COmmon Business Oriented Language), FORTRAN (FORmula +TRANslation) en ALGOL (ALGOrithmic Language). De laatste +twee zijn de stamvaders van de moderne programmeertalen. +BASIC (Beginners All-purpose Symbolic Instruction Code) is +duidelijk afgeleid van (een vroege vorm van) FORTRAN. BASIC +was in principe alleen bedoeld als oefentaal voor beginnende +programmeurs, en de ontwerpers ervan hebben dan ook geen +moeite gedaan om er structuur in aan te brengen, iets waar +ook de moderne BASIC's nog steeds last van hebben. + +ALGOL was de eerste programmeertaal die met enig beleid is +ontworpen. Een speciaal comitee, voornamelijk bestaand uit +wiskundigen, heeft begin zestiger jaren de defintie van deze +taal in een rapport vastgelegd. Uit deze taal is later +PASCAL voortgekomen. (PASCAL is gelukkig eens geen acroniem: +de naam komt van Blaise Pascal, een Frans wiskundige van een +paar eeuwen terug.) De syntax van PASCAL is bijna identiek +aan die van ALGOL, en is op sommige punten zelfs versimpeld +om het de compiler makkelijk te maken. Wel kent PASCAL meer +data-typen dan ALGOL. + +De taal C is in principe ook afgeleid van ALGOL, maar niet +direct. Ertussen zitten nog de talen BCPL en B, die speciaal +voor de relatief kleine computers in de PDP-serie bedoeld +waren. Ook C was in eerste instantie bedoeld voor +systeemprogrammatuur op een PDP-11 onder UNIX, en +instructies als "++" zijn in de taaldefinitie gekomen om +optimaal gebruik te maken van de instructieset van deze +processor. (Overigens, de instructieset van de "moderne" +68000 processor vertoont opmerkelijke overeenkomsten met die +van de PDP-11.) + +In C kun je heel abstract programmeren, maar ook heel +effici�nt en machinespecifiek. Dit maakt C zelfs in zijn +basisvorm een krachtige en prettige programmeertaal. Andere +talen - en met name Turbo PASCAL - moeten allerlei +niet-gestandaardiseerde uitbreidingen maken om die +flexibiliteit te benaderen. Evenaren is zelfs bijna +onmogelijk, zeker waar het het gebruik van pointers betreft. +Het nadeel is wel dat er hele obscure bug's kunnen ontstaan, +en dat is waarschijnlijk de reden dat er zo weinig MSX-ers +in C programmeren. + +Veel C-compilers staan ook toe om zelf bibliotheken te maken +met nieuwe functies, en die ook APART te compileren. In +ASCII-C is zelfs het grootste deel van de +standaardbibliotheek in C zelf geschreven. Dit alles maakt +het mogelijk om zgn. "modulair" te programmeren, wat wil +zeggen: een groot programma in kleinere deelprogramma's op +te splitsen en apart te programmeren. Dit houdt de +programmeerarbeid niet alleen overzichtelijk, maar het maakt +het ook gemakkelijk om meerdere mensen aan een programma te +laten werken door het werk eenvoudig te verdelen. + +De taal C is - net als PASCAL - een "kleine" +programmeertaal, wat inhoudt dat de taaldefinitie klein en +compact is gehouden. I/O valt in principe buiten deze +definitie, maar er zijn in de loop der tijden toch bepaalde +conventies en standaardbibliotheken ontstaan, waar we ons in +de cursus maar van zullen bedienen. Eveneens is C een zgn. +"free format" taal, wat inhoudt dat je de in de +programmatekst willekeurig spaties, tabs of crlf's +(newlines) mag gebruiken, mits er op die manier geen namen, +strings of symbolen in stukken worden gesneden. Dit in +tegenstelling tot bijvoorbeeld COBOL, waar voor ieder +programmaelement is vastgelegd op welke kolom die moet +beginnen. + +Ook in de cursus zal er aan de hand van voorbeelden de +verschillende taalelementen worden uitgelegd. Dus eerst een +voorbeeldprogramma, gevolgd door de uitleg. Tussendoor zal +wat dieper op bepaalde onderwerpen worden ingegaan. + +``` +| /* | +| De listings in de tekst staan tussen deze tekens. Ze | +| maken geen deel uit van het programma. Ze zijn alleen | +| bedoeld om duidelijk te maken waar de listings in de | +| tekst staan. Waar een enkel statement in de tekst wordt | +| besproken, zijn die dingen niet gebruikt, alleen | +| volledige programma's! | +| */ | +``` + +## M I J N E E R S T E C - P R O G R A M M A +``` +| | +| #include | +| | +| /* Mijn eerste programma */ | +| | +| main() { | +| | +| printf("Hello, world!\n"); | +| | +| } | +| | +``` +Dit is het equivalent van het BASIC-programma: +``` + 10 REM Mijn eerste programma + 20 PRINT "Hello, world" + 20 END +``` +Om een of andere reden wordt dit C-programma altijd gebruikt +voor de beginner, en met zo'n oude traditie wil ik niet +breken. + +De eerste regel +``` + #include +``` +is bedoeld om een aantal standaardfuncties, -definities en +-constanten beschikbaar te maken voor de programmeur. In +feite betekent het alleen dat het file "STDIO.H" (staat voor +STandarD I/O) wordt opgenomen in het programma. Dit file kun +je ook gewoon bekijken met TYPE (onder DOS, natuurlijk). De +'<' en de '>' stellen een soort quotes voor, maar de gewone +'"' kan meestal ook. Met '#include "file"' kan overigens +iedere file in de programmatekst worden opgenomen, met +bijvoorbeeld eigen definities of constanten. Wel moet zo'n +'#include' helemaal aan het begin van een regel staan! (Dit +is dus een uitzondering op het bovengenoemde free-format). + +De volgende regel is een commentaarregel. De compiler +negeert alles tussen '/*' en '*/'. + +Vervolgens staat er +``` + main() { +``` +Dit is in feite een functiedefinitie, maar zonder +parameters, zodat er niets tussen de haakjes staat. In de +ruimte tussen ')' en '{' moeten de datatypes van de +parameters worden gegeven, dus die ruimte blijft ook leeg. +De naam 'main' is een bijzondere in C; het geeft aan dat dit +het hoofdprogramma (main program) is. Welke volgorde je je +functies ook hebben, de uitvoering van het programma begint +altijd bij 'main'. Na de '{' volgt de daadwerkelijke +functie, de zgn. 'body'. Hier bestaat die body uit een +statement, namelijk: +``` + printf("Hello, world!\n"); +``` +'printf' is een I/O functie, de naam staat voor "print +formatted", zoiets als PRINT USING in BASIC, maar je kan er +ook gewoon strings mee afdrukken. De '\n' aan het eind van +de string betekent dat er naar een nieuwe regel moet worden +gesprongen. De '\' (backslash) is een zgn. 'escape +character', wat aangeeft dat het volgende karakter een +bijzondere betekenis heeft. '\n' staat dus voor newline, +meestal een 'linefeed' met ASCII code 10, '\t' staat voor +tab, code 9, en zo zijn er nog een aantal. Met '\nnn', +waarbij nnn een OCTALE constante is kun je alle ASCII codes +van 0 tot 255 (0 tot 377 octaal, is dat) gebruiken, zelfs +als de editor daar moeite mee heeft! + +De ';' aan het eind van de regel geeft het eind van het +statement aan. Hoewel dit dus veel lijkt op PASCAL is er een +belangrijk verschil: in PASCAL scheidt de puntkomma twee +statements, en in C is het de afsluiting van een statement! +Als je daar niet op verdacht bent kan dat onverwachte +foutmeldingen opleveren! + +De '}' aan het eind van het programma geeft aan dat de +functie ten einde is. PASCAL-programmeurs kunnen +eenvoudigweg voor de '{' 'BEGIN' lezen en voor de '}' 'END' +om een en ander duidelijker te laten worden. + +Nu is het nog zaak om het programma te compileren en +eventueel te linken, en we hebben een programma dat +vriendelijk hallo zegt. Niet het meest spectaculaire +programma ter wereld, maar alle begin is eenvoudig. + + +## S I M P E L E D A T A T Y P E N I N C + +Net als BASIC en PASCAL kent C een aantal simpele datatypen, +die - net als PASCAL - als basis kunnen dienen voor +ingewikkelder datatypen. In deze paragraaf worden deze typen +besproken. Met deze datatypen kunnen we variabelen cre�ren. + +De basistypen zijn: + +TYPE GROOTTE BEREIK OMSCHRIJVING +------------------------------------------------------------ +char 1 byte 0..255 of -128..127 karakter +int 2 bytes -32768..32767 getal met teken +unsigned 2 bytes 0..65535 getal zonder teken +long 4 bytes -2147483648..2147483647 getal met teken +float 4 bytes +/- 1.0E+/-36 glijdende komma, 6 cijfers +double 8 bytes +/- 1.0E+/-36 glijdende komma, 13 cijfers + +De grootte en de precieze nauwkeurigheid van de 'float' en +de 'double' hangen nogal af van de implementatie, het zijn +dus slechts richtwaarden. Bovendien onbreekt er in de meeste +C-compilers voor MSX ieder spoor van floating-point typen, +waardoor e.e.a. nogal academisch is. Ook het 'long' type +ontbreekt meestal, wat eigenlijk veel lastiger is, omdat +sommige standaard bibliotheekfuncties daarmee zijn +gedefinieerd. + +De gegeven groottes en bereiken zijn overigens minima, maar +worden op 8-bitters, zoals onze Z-80 bij mijn weten nooit +overschreden. Het char-type moet overigens altijd 1 byte +groot zijn. De precieze grootte van elk datatype is altijd +op te vragen met de 'SIZEOF' pseudo-operator. Zo moet +'SIZEOF(char)' dus altijd de waarde 1 opleveren. (Het wordt +een pseudo-operator genoemd omdat er niets wordt uitgerekend +door het programma: de compiler vult er eenvoudigweg een +constante voor in). + +Sommige datatypen hebben ook pseudoniemen. Hier volgt een +lijstje: + + short int = int (op 8-bit computers, tenminste) + unsigned int = unsigned + long int = long + long float = double + + +## V A R I A B E L E N I N C + +Dat we nu de simpele data-types kennen in C is heel +plezierig, maar we moeten natuurlijk daar ook variabelen mee +kunnen declareren, d.w.z. cre�ren. Dit moeten we, net als in +PASCAL, zelf doen. BASIC cre�ert een nieuwe variabele op het +moment dat die voor het eerst gebruikt wordt. + +De naam van variabelen mag bestaan uit letters, cijfers en +'_', maar mag niet met een cijfer beginnen. Ook kan het zijn +dat de lengte van een naam beperkt is, maar dat hangt weer +van de compiler af. + +Het declareren van een variabele gaat als volgt: + + ; + +of: + + ,,.......; + +In het laatste geval worden er een aantal variabelen +gedeclareerd van hetzelfde type. De ';' aan het eind is +wederom verplicht! + +Voorbeelden: +``` + int x; + int y, z; + char lange_naam; + unsigned catch22; + float blub, blubblub; +``` + +## V O O R B E E L D P R O G R A M M A 2 E E N K W A D R A T E N T A B E L M A K E N + +In dit programma kan kennis worden gemaakt met wat simpel +gereken in C en het gebruik van variabelen. Ook komt de +eerste lus aan bod, de do..while lus. +``` +| | +| #include | +| | +| #define MAXWAARDE 10 | +| | +| /* Rekenen en de do..while lus */ | +| | +| main() { | +| | +| int waarde,kwadraat; | +| | +| waarde = 0; | +| | +| do { | +| kwadraat = waarde * waarde; | +| printf("Waarde = %4d Kwadraat = %4d\n", waarde, | +| kwadraat); | +| ++waarde; } | +| while (waarde <= MAXWAARDE); | +| | +| printf("\n\nThat's all folks!\n"); | +| } | +| | +``` +De '#include' kennen we nog van het vorige programma, maar +de '#define' is nieuw. Het is echter een simpele, doch +krachtige manier om de ene tekst door de andere te +vervangen. Iedere keer als de compiler dus het hele (!!) +woord 'MAXWAARDE' tegenkomt, wordt het door '10' vervangen. +De computer "ziet" dus: +``` + while (waarde <= 10); +``` +Maar 'MAXWAARDES' zou niet veranderd worden, omdat per heel +woord gekeken wordt. Hiervoor geldt hetzelfde als voor de +namen van variabelen: letters, cijfers en '_' mogen worden +gebruikt. De tekst, waarin dat woord wordt verandert hoeft +daar niet aan te voldoen. Met de regel +``` + #define ACCOLADE_OPEN { +``` +is dus niets verkeerds. + +Hoewel je woorden op die manier door willekeurige andere +tekst kunt vervangen, wordt het meestal alleen gebruikt om +constanten te definieren, zoals hierboven. Een van de +conventies in C is om zulke constanten altijd in +hoofdletters te schrijven, vanwege de duidelijkheid. Zulke +definities mogen ook weer binnen andere '#define's gebruikt +worden. Dus +``` + #define MAXKWADRAAT MAXWAARDE*MAXWAARDE +``` +is prima. + +Nadat we in 'main' zijn aangeland, worden de variabelen +'waarde' en 'kwadraat' gedeclareerd, beide van het int-type. +Vervolgens wordt met +``` + waarde = 0; +``` +de variabele 'waarde' nul gemaakt. In PASCAL zou ':=' +gebruikt worden in plaats van de '=', maar verder is alles +hetzelfde. + +Vervolgens gaan we de do..while lus binnen, maar daar heb ik +het later over. Dan staat er: + + kwadraat = waarde * waarde; + +De '*' betekent dus niets anders dan vermenigvuldiging, +tenminste als binaire operator. (Dat wil zeggen dat er twee +getallen nodig zijn bij een vermenigvuldiging, want 'bi' +betekent 'twee'.) Als unaire operator - 'un' is '1' +-betekent dat sterretje iets heel anders, maar daarover een +andere keer. + +Hierna komt: +``` + printf("Waarde = %4d Kwadraat = %4d\n", waarde, kwadraat); +``` +wat ons leert hoe je met 'printf' ook getallen kunt +afdrukken. Hiervoor is in de string tweemaal het gedeelte +'%4d' opgenomen, om respectievelijk 'waarde' en 'kwadraat' +op het scherm te krijgen. Het procentteken geeft aan dat er +iets moet worden afgedrukt, de '4' geeft het aantal posities +aan waarin dat moet gebeuren, en de 'd' tenslotte geeft aan +dat het decimaal moet gebeuren. Er kan ook 'x' gebruikt +worden voor hexadecimale uitvoer, of 'u' als er een unsigned +moet worden afgedrukt. En dat is nog maar een klein deel van +alle mogelijkheden, maar voorlopig genoeg, lijkt me. Als +'waarde' 5 is en 'kwadraat' dus 25, komt er dit op het +scherm: + + Waarde = 5 Kwadraat = 25 + +gevolgd door een newline. Let goed op de lege ruimte voor de +getallen, doordat we een veldbreedte van 4 hebben opgegeven. +Als het getal te breed is voor het veld, wordt het getal +niet smaller gemaakt maar toch helemaal afgedrukt. Door als +veldbreedte dus '0' op te geven, of de veldbreedte weg te +laten (wat op hetzelfde neerkomt) wordt dus zo weinig +mogelijk ruimte gebruikt. + +De functie printf mag een variabel aantal parameters hebben, +maar de format-string is verplicht. Daaraan kan de functie +aflezen hoeveel parameters er nog volgen. Twee maal de '%4d' +in bovenstaand voorbeeld gaf dus aan dat er na de +format-string nog twee parameters volgden van het type +'int'. Een functie met een variabel aantal parameters wordt +een 'variadic function' genoemd. Een aantal compilers staan +toe zelf dit soort functies te schrijven, maar de preciese +details hoe je dat kan doen verschilt per compiler. + +Daarna staat er +``` + ++waarde; +``` +Dit is voor niet-C programmeurs onbegrijpelijk koeterwaals. +Het betekent echter alleen: tel 1 bij 'waarde' op. We hadden +dus ook kunnen schrijven: +``` + waarde = waarde + 1; +``` +De andere schrijfwijze is korter en sneller, wat in dit +voorbeeld misschien niet zo erg naar voren komt, maar in +iets ingewikkelder berekeningen wel. + + +Dan nu de do..while lus. Als algemene vorm heeft zij: + + do while (); + +Vertaald in het Nederlands: + + HERHAAL een statement ZOLANG (deze uitdrukking NIET nul is); + +Dan hebben we meteen een probleem, want we hebben niet een +enkel statement, maar drie! De oplossing is gelukkig +eenvoudig want als we een aantal statements achter elkaar +tussen '{' en '}' zetten, "ziet" C het als een enkel +statement. Dit wordt een 'compound statement' genoemd. + +Aan het einde van de lus staat: +``` + while (waarde <= MAXWAARDE); +``` +Lees voor '<=' 'kleiner of gelijk aan'. De '<=' is een +vergelijkingsoperator die 0 oplevert als de vergelijking +niet waar is, en een waarde ongelijk aan 0 als de +vergelijking klopt. + +Zolang 'waarde' in ons voorbeeld kleiner of gelijk is aan +10, klopt de vergelijking, en levert dus een waarde ongelijk +aan 0 op. Hierdoor wordt het programma weer vanaf het begin +van de lus doorlopen. Zodra 'waarde' groter dan 10 is +geworden, wordt niet meer naar het begin van de lus gegaan, +en vervolgt het programma gewoon. Hierdoor krijgen een +keurig lijstje met de getallen 0 t/m 10 en de kwadraten +daarvan. + +Na de boodschap + + That's all folks! + +stopt nu het programma. + +Nog even een lijstje met de vergelijkingsoperatoren die C +rijk is: + + > groter dan + >= groter dan, of gelijk aan + < kleiner dan + <= kleiner dan, of gelijk aan + == gelijk aan (jawel, twee is-gelijk tekens!) + != ongelijk aan + + + +Volgende keer meer. + +Vragen, opmerkingen of dreigbrieven aan: + + Stichting Sunrise + T.a.v. Robert Amesz + Postbus 2146 + 2400 CC Alphen a/d Rijn + +Of plaats een bericht in dit BBS (wel zo handig, nietwaar?): + + Future Base + Online ma-vr 22:00-06:00 za+zo 21:00-06:00 + Sysop: Johan Gijsman + Tel. 071-222380 + + +Een nuttig naslagwerkje over C dat voor plm. � 7,-- bij de +Slegte te koop is: + + F. Wagner-Dobler + "Zakboek C-language" + Delfia-Press, Rijswijk, 1987 + ISBN 90-6449-024-4 + +Dit is geen leerboek! Er staat echter bijzonder veel +informatie in. + +Robert Amesz \ No newline at end of file diff --git a/sunrise_special/2/programmeer_taal_c_2.md b/sunrise_special/2/programmeer_taal_c_2.md new file mode 100644 index 0000000..c275e17 --- /dev/null +++ b/sunrise_special/2/programmeer_taal_c_2.md @@ -0,0 +1,272 @@ +# D E P R O G R A M M E E R T A A L C ( 2 ) + + + +## I N L E I D I N G + +In de vorige aflevering hebben we wat ge�xperimenteerd met +wat simpel rekenwerk in C. Deze aflevering gaan we eens wat +nader kijken naar het rekenen in C, want dat verschilt nogal +van PASCAL en BASIC. Vooral de filosofie erachter is nogal +anders. + +Zo kent C geen rekenkundige statements, alleen uitdrukkingen +(expressions)! Om van een uitdrukking een statement te maken +volstaat het er een ';' achter te zetten. Deze manier van +werken maakt het mogelijk allerlei onzinnige statements te +maken, die zonder problemen door de compiler verwerkt +worden. Kijk dus uit, want +``` + 1; +``` +is foutloos C, alleen gebeurt er weinig. + + +## R E K E N K U N D I G E U I T D R U K K I N G E N + +Een expression levert altijd een waarde op, maar als je er +een statement van maakt wordt er verder niets met die waarde +gedaan. De '=' (toewijzing, oftewel assignment) is ook een +operator, en geen (deel van) een statement. De waarde van +``` + x = 35 +``` +is gewoon 35, dus de uitdrukking die rechts van het '=' +teken staat. Dit heeft grote voordelen als je effici�nt en +compact wil programmeren. Zo maakt de uitdrukking +``` + y = (x = 35) + 2 +``` +x gelijk aan 35, en y gelijk aan 37, wat ook het resultaat +van de hele uitdrukking is. De haakjes zijn hier nodig, +omdat de '+'-operator een hogere prioriteit heeft dan de '=' +operator. de uitdrukking +``` + y = x = 2 + 35 +``` +zou zowel x als y gelijk maken aan 37. De prioriteiten van +de vele operators die C kent - en er zijn er ruim 40! - zijn +zelfs voor geoefende C-programmeurs nauwelijks uit het hoofd +te leren, vandaar dat het gebruik van haakjes, zelfs als dit +niet strikt nodig is, vaak is aan te raden. De gewone +rekenoperaties ('+' '-' '*' '/') hebben echter de prioriteit +die je ervan verwacht. + +Een grote bron van fouten is het verwisselen van de '=' en +de '==' operator. Laatstgenoemde is een vergelijkingoperator +(zie de vorige aflevering) die veel gebruikt wordt, maar +soms wordt er wel eens een enkele '=' getypt als er een +dubbele bedoeld wordt. Vergelijk eens de volgende lussen: +``` + do { /* hier allerlei statements */ } + while (x == 10); +``` +en +``` + do { /* hier allerlei statements */ } + while (x = 10); +``` +Je leest gemakkelijk over het verschil heen, maar de eerste +lus wordt be�indigd als x ongelijk aan 10 wordt, en in de +tweede lus wordt x altijd 10 gemaakt. Bovendien is de waarde +van de uitdrukking 'x = 10' gelijk aan 10 (niet nul, dus) en +wordt de lus nooit be�indigd! De compiler echter heeft geen +enkele moeite met deze twee lussen, en geeft ook geen +waarschuwing of foutmelding. De prijs van de flexibiliteit +van C is dus zorgvuldiger nakijken van het programma door de +programmeur. + + + +## D E A L G O R I T H M E V A N E U C L I D E S +``` +| | +| #include | +| | +| | +| /* Bepaal de grootste gemene deler van twee getallen */ | +| int ggd(grootste, kleinste) | +| int grootste, kleinste; | +| { | +| | +| int temp, rest; | +| | +| /* Zorg ervoor dat 'grootste' het grootste getal bevat */| +| /* Verwissel ze zonodig */| +| if (grootste < kleinste) { | +| temp = kleinste; kleinste = grootste; | +| grootste = temp; | +| } | +| | +| /* Het daadwerkelijke algorithme */ | +| | +| while (rest = (grootste % kleinste)) { | +| grootste = kleinste; | +| kleinste = rest; } | +| | +| return kleinste; | +| | +| } /* einde van functie ggd() */ | +| | +| | +| /* Hoofdprogramma */ | +| main() { | +| | +| int getal1, getal2; | +| | +| getal1 = 69; | +| getal2 = 253; | +| | +| printf("De grootste gemene deler van %d en %d is %d\n",| +| getal1, getal2, ggd(getal1, getal2)); | +| | +| printf("\nEinde programma\n\n"); | +| } | +| | +``` + +In dit programma worden heel wat nieuwe taalelemenen +ge�ntroduceerd: allereerst het gebruik van functies, het +if-statement, een iets andere versie van de reeds bekende +do..while lus, en het return-statement. + +Om te beginnen iets over functies, ofwel subroutines, in C. +In tegenstelling tot PASCAL kent C geen procedures. Dit is +geen groot gemis, aangezien we functies als procedures +kunnen gebruiken. De functiewaarde, die de functie geeft, +wordt dan eenvoudig niet gebruikt. + +Met de regels +``` + int ggd(grootste, kleinste) + int grootste, kleinste; +``` +geven we aan dat de definitie van de functie 'ggd' volgt. +(Voor functienamen gelden dezelfde regels als namen van +variabelen). Het 'int' voor 'ggd' laat de compiler weten dat +de waarde die de functie teruggeeft van het type 'int' is. + +De namen na het '(' zijn de parameters van de functie. Er +mag een willekeurig aantal parameters, door komma's +gescheiden, volgen (dus ook 0). In ons geval zijn dat er +twee, 'grootste' en 'kleinste'. + +In de volgende regel (of regels) worden de typen van de +parameters gespecificeerd. Dit gebeurt alsof het variabelen +zijn. Zo vreemd is dat niet, want binnen de functie (na de +'{') mogen de parameters precies als variabelen gebruikt +worden. In het bovenstaande geval hebben we dus twee +parameters van het type 'int'. + +Vervolgens worden er twee variabelen gedeclareerd van het +type 'int'. Net als in PASCAL zijn variabelen die binnen een +functie worden gedeclareerd - en daar rekenen we de +parameters van de functie ook onder - alleen binnen de +functie bekend. Dus 'grootste', 'kleinste', 'rest' en 'temp' +kunnen alleen binnen 'ggd' gebruikt worden, en zijn vanuit +'main' onbereikbaar. Wie denkt dit te kunnen omzeilen door +binnen 'main' deze variabelen opnieuw te declareren komt +bedrogen uit: de variabelen hebben weliswaar dezelfde naam, +maar zijn toch andere variabelen! + +Dit laatste betekent dat de C-programmeur zich geen zorgen +hoeft te maken of een bepaalde naam al binnen een andere +functie gebruikt wordt. Wil hij toch dat een bepaalde +variabele door verschillende functies gebruikt kan worden, +dan moet die variabele buiten een functie worden +gedeclareerd, d.w.z. aan het begin van het programma, of +tussen de functies in. + +De regels +``` + if (grootste < kleinste) { + temp = kleinste; kleinste = grootste; grootste = temp; } +``` +is een if-statement in C. Het lijkt veel op dat van BASIC of +PASCAL, alleen ontbreekt hier 'THEN'. Het 'THEN' is echter +impliciet! De algemene vorm van een if-statement is: + + if () + +Als een waarde oplevert die niet gelijk is aan +nul, dan wordt uitgevoerd. In het bovenstaande +voorbeeld moesten we dus weer een compound-statement +gebruiken. C kent ook een if..else statement: + + if () else + +Als een waarde oplevert die niet gelijk is aan +nul, dan wordt uitgevoerd, in het andere geval +. + +Wat de bedoeling is van het if-statement in het +voorbeeldprogramma staat al in de ervoor staande +commentaarregel! + +Nu krijgen we een nieuwe vorm van het while-statement, +namelijk: + + while () + +Dit werkt precies als het do..while statement, alleen wordt +er in het begin van de lus getest, en niet aan het eind. Dit +houdt tevens in dat niet wordt uitgevoerd, als + meteen al de waarde nul oplevert. Het programma +gaat dan verder na . In de do..while lus wordt + tenminste 1 keer uitgevoerd. + +De , zoals die in het voorbeeld wordt gebruik, +maakt al aardig gebruik van de mogelijk heden van C. Het '%' +in + + rest = (grootste % kleinste) + +betekent hetzelde als MOD in BASIC of PASCAL, de rest na +deling dus. Deze waarde wordt, heel toepasselijk, aan de +variabele 'rest' toegewezen, wat ook de uitkomst van deze +uitdrukking is. Als 'rest' dus nul wordt, wordt de lus niet +(meer) doorlopen. + +Na het compound statement na 'while' volgt een onbekend +statement, namelijk + + return kleinste; + +BASIC-programmeurs zullen nu de oren spitsen. Inderdaad +be�indigt een return statement een functie (subroutine). De +algemene vorm is: + + return; + +of + + return ; + +In het eerste geval wordt de functie be�indigd, zonder dat +er een functiewaarde wordt teruggegeven aan het programma +dat de functie aanriep, in het tweede geval gebeurt dat wel +(namelijk de waarde van ). In ons voorbeeld +wordt de inhoud van 'kleinste' gereturnd. Een kale 'return;' +aan het einde van een functie is overigens nooit nodig: de +compiler regelt dat zelf wel. + +De functie wordt nu afgesloten met een '}'. Het kan +eenvoudig bewezen worden dat deze functie inderdaad de +grootste gemene deler van twee getallen levert, maar dat +valt buiten het bestek van deze reeks. Een oefening voor de +lezer wellicht? Het is misschien interessant te weten dat +dit de oudst bekende algorithme ter wereld is. Zij dateert +van ruim voor het begin van onze jaartelling! + +Het hoofdprogramma - na 'main' - moet voor de trouwe lezer +weinig problemen opleveren. In 'printf' kun je zien hoe de +functie 'ggd' kan worden aangeroepen. Overigens mogen zelfs +een achter een functie met nul parameters de haakjes niet +worden weggelaten, dit in tegenstelling tot PASCAL. Doe je +dit toch dan krijg je bij de meeste compilers geen +foutmelding! (Voor de ge�nteresseerden: in plaats van de +functiewaarde krijg je dan de pointer naar de functie, +oftewel het adres van de functie. Over pointers wil ik het +echter pas in de volgende aflevering hebben). + +Robert Amesz \ No newline at end of file diff --git a/sunrise_special/2/rechtstreeks_via_pcm_afspelen.md b/sunrise_special/2/rechtstreeks_via_pcm_afspelen.md new file mode 100644 index 0000000..a9710e3 --- /dev/null +++ b/sunrise_special/2/rechtstreeks_via_pcm_afspelen.md @@ -0,0 +1,123 @@ +# R E C H T S T R E E K S V I A P C M A F S P E L E N + + +De PCM afspeelroutines in de turbo R zijn via een BIOS call +te gebruiken, maar kunnen dan maar op een beperkt aantal +snelheden ingesteld worden. De maximale sample-snelheid is +16 kHz. Dat is goed voor een redelijk geluid. PCM samples +voor de Amiga, PC (Soundblaster) en Apple Macintosh worden +echter regelmatig op snelheden van 22 tot 44 kHz opgenomen, +en klinken op een turbo R dan te langzaam als hiervoor de +BIOS wordt gebruikt. Sample-data rechtstreeks naar de PCM +sturen via de D/A-poorten biedt de oplossing. Het is ook +mogelijk samples met een hoge snelheid (dus hogere +kwaliteit) op te nemen door de BIOS te passeren, maar in +deze tekst beperk ik me tot het afspelen van samples. Ik heb +dit uitgezocht voor toepassing in het programma PLAYSMP, de +universele sample-speler voor iedere MSX2, MSX2+ en turbo R +(shareware t.g.v. Jos-Tel, staat ook op Sunrise Magazine +#6). + +Bij het afspelen van een sample via de BIOS doet de turbo R +het volgende: + +1. Kijk welke processor actief is + Is dit de Z80? + Dan bewaar het resultaat en schakel om naar R800-ROM +2. Reset de PCM (stel hem in op schrijven) +3. Voor TELLER=1 tot LENGTE (sample) + Lees een databyte + Stuur hem naar de PCM +LUS1: PCM klaar? + Als niet klaar, dan ga naar LUS1 +LUS2: Wachttijd verstreken (i.v.m. afspeelsnelheid)? + Als niet verstreken dan ga naar LUS2 + Verlaag TELLER, volgende byte +4. Reset de PCM +5. Was de oorspronkelijke processor Z80? + Dan schakel die weer in +6. Klaar + + +Om nu een hogere afspeelsnelheid te bereiken, kunnen we de +wachtlussen in de PCM routine simpelweg overslaan. Het is +ook niet noodzakelijk de processor om te schakelen, +aangezien een Z80A snel genoeg is voor samples van 44 kHz. +Wil je echter de zekerheid dat samples altijd op dezelfde +snelheid worden afgespeeld, dan moet je er wel voor zorgen +dat de processor altijd in dezelfde 'mode' staat. + + +## P R O G R A M M A + +Hieronder vind je een voorbeeld van een ML-subroutine waarin +een PCM sample op adres HL en met lengte BC wordt +afgespeeld. Het voorbeeld staat ook op disk onder de naam +PCMPLAY.ASC. + +``` +;SpeelPCM + +PCM: CALL RESPCM ;reset de PCM + CALL PLAY ;speel de sample af +RESPCM: DI + LD A,80H ;reset de PCM + OUT (0A4H),A + LD A,3 + OUT (0A5H),A + EI + RET ;klaar + +PLAY: LD A,(HL) ;pak byte op adres in HL + OUT (0A4H),A ;stuur naar PCM datapoort + INC HL ;verhoog pointer HL + DEC BC ;verlaag teller BC + LD A,B + OR C ;is BC al 0? + JR NZ,PLAY ;nee, volgende byte + RET ;ja, klaar +``` + +Bovenstaande afspeelroutine zal onder normale omstandigheden +veel te snel zijn, ook als de Z80 ingeschakeld is. Daarom +moet in de PLAY routine een vertragingslus worden ingebouwd: + +``` +WACHT: PUSH BC ;bewaar teller + LD B,WACHTTIJD ;wachten (0..255) +LUS: DJNZ LUS ;verlaag B, als niet 0 ga + ; naar LUS + POP BC ;herstel teller +``` + +Deze wachtlus is bijvoorbeeld in te bouwen tussen de INC HL +en DEC BC instructies. De BIOS van de turbo R bevat geen +wachtlus zoals hierboven aangegeven, maar bepaalt de +afspeelsnelheid aan de hand van terugmeldingen van de PCM, +wat een stuk nauwkeuriger is maar de al genoemde nadelen +heeft. Onderstaande routine is een stukje disassembly uit de +turbo R BIOS, dat thuishoort op de plaats waar hierboven +alleen de instructie OUT (0A4H),A staat: + +``` + OUT (0A4H),A ;stuur byte naar PCM +PAKPCM: IN (0A4H),A ;lees byte uit PCM + OR A ;nul? + JR Z,PAKPCM ;ja, wacht tot niet 0 + EXX ;alternatieve registers +PAKPC2: IN A,(0A4H) ;lees byte uit PCM + CP E ;gelijk aan E'? + JR NZ,PAKPC2 ;nee, herhaal + EXX ;terug naar normale + ; registers +``` + +Het moge duidelijk zijn dat de snelheid die de aanroepende +routine aan de BIOS-CALL PLAYPCM heeft doorgegeven inmiddels +in register E' is gezet (EXX; LD E,A; EXX). De turbo R scant +tijdens het afspelen van een sample ook nog de +toetsenbord-matrix om te kijken of de STOP-toets wordt +ingedrukt. Ik laat het aan de fantasie van de lezer over om +daar zelf een routine voor te schrijven. + +Pierre Gielen \ No newline at end of file diff --git a/Sunrise Special/2/Resource.md b/sunrise_special/2/resource.md similarity index 100% rename from Sunrise Special/2/Resource.md rename to sunrise_special/2/resource.md diff --git a/sunrise_special/2/stereo_scc.md b/sunrise_special/2/stereo_scc.md new file mode 100644 index 0000000..994c42b --- /dev/null +++ b/sunrise_special/2/stereo_scc.md @@ -0,0 +1,20 @@ +# S T E R E O S C C + +Het idee van het ombouwen van de SCC naar een zogenaamde +stereo SCC is niet nieuw. Maar omdat ik nog nooit ergens een +tekst hierover ben tegengekomen, heb ik deze tekst maar even +geschreven. Voor de knutselaar is het een leuk projectje! + +Waarschuwing: Het uitvoeren van deze ingreep in uw SCC is op +eigen risiko, gaat er iets mis dan vervalt uw garantie. +Sunrise is op geen enkele manier aansprakelijk voor enige +schade die uit dit project kan voortvloeien! + +Het ombouwen is eigenlijk gigantisch simpel, maar desondanks +heb ik de volledige beschrijving maar even als DP file op +deze schijf gezet. Laad deze in met Dynamic Publisher (naam +van de file: STEREOSC.PCT). + +Veel plezier met de "stereo SCC" en tot een volgende keer! + +Haiko de Boer \ No newline at end of file diff --git a/sunrise_special/2/vdp_cursus_1.md b/sunrise_special/2/vdp_cursus_1.md new file mode 100644 index 0000000..487713f --- /dev/null +++ b/sunrise_special/2/vdp_cursus_1.md @@ -0,0 +1,418 @@ +# M S X 2 / 2 + V D P C U R S U S ( 1 ) + + + +## H E R H A L I N G + +Deze cursus is al eerder verschenen op de ClubGuide en +Sunrise Magazine, vanaf ClubGuide #7. Omdat ik tientallen +brieven van lezers heb gekregen die de eerste delen hebben +gemist, heb ik besloten om de cursus opnieuw te publiceren, +nu op de Sunrise Special. + +Een andere reden om de cursus opnieuw te publiceren is dat +ik intussen meer weet over de VDP, zodat ik de cursus nog +beter kan maken. De tekst zal ik grotendeels herschrijven, +de oude cursus dient eigenlijk vooral als basismateriaal. Ik +zal vooral meer aandacht besteden aan het programmeren van +de VDP in ML. Hierdoor is de VDP cursus op herhaling ook +interessant voor de lezers die de cursus al vanaf deel 1 +hebben gevolgd. Veel plezier met de VDP cursus op herhaling! + + +## I N L E I D I N G + +Je kunt veel meer uit de VDP halen door hem rechtstreeks aan +te sturen. Zelfs in BASIC zijn er al aanmerkelijke +snelheidsverbeteringen mee te realiseren. Alle schitterende +VDP truuks die u in de demo's op de Sunrise Picturedisk kunt +bewonderen worden bereikt door het rechtstreeks aansturen +van de VDP. Het moet in principe mogelijk zijn dat u aan het +eind van de cursus ook dergelijke truuks met de VDP kunt +uithalen, mits er natuurlijk voldoende kennis van ML +aanwezig is. + +Dit artikel is zowel voor MSX2 als voor MSX2+-gebruikers +bestemd. De V9938 (MSX2) en de V9958 (MSX2+) zijn namelijk +grotendeels hetzelfde. Alleen waar er verschillen zijn, zal +het artikel opsplitsen in een MSX2 en een MSX2+ deel. De +informatie in dit artikel is zeer betrouwbaar, want het +meeste komt rechtstreeks uit de Technical Data Books van +Yamaha. (Inmiddels is er ook de turbo R, die echter dezelfde +VDP bezit als de MSX2+.) + + +## L E Z E N E N S C H R I J V E N V A N V D P - R E G I S T E R S + +Voordat we iets met de VDP kunnen doen is het eerst +noodzakelijk om te weten hoe de VDP kan worden aangestuurd. +Het aansturen van de VDP registers kan op drie manieren, +namelijk in BASIC met het VDP commando, in machinetaal met +BIOS calls en in machinetaal door rechtstreeks I/O poorten +te lezen/schrijven. Ik zal deze methodes nu ��n voor ��n +bespreken. + + +## B A S I C + +In BASIC kun je VDP-registers uitlezen of beschrijven met +het VDP(N) commando. Voor N moet je meestal NIET het regis- +ter nummer invullen, zoals die verder in dit artikel worden +gebruikt. Een register wordt aangegeven met R#nummer +(bijvoorbeeld R#23) en een statusregister met S#nummer. In +BASIC moet je de volgende omrekentabel gebruiken: +``` +Register: N: Lezen/Schrijven: +------------------------------------------------------------ +R#00-R#07 0- 7 L/S +R#08-R#23 9-24 L/S +R#25-R#27 26-28 (alleen 2+) L/S +R#32-R#46 33-47 L/S +S#00 8 L +S#01-S#09 -1 - -9 L +------------------------------------------------------------ +``` +Schrijven doe je met VDP(N)=waarde en lezen met W=VDP(N). +Bijvoorbeeld VDP(10)=0 of PRINT VDP(1). + + +## M A C H I N E T A A L + +In machinetaal kun je voor het lezen/schrijven van VDP +registers de routines gebruiken die al in het ROM van je +MSXje zitten. Dat zijn: + +&H0047 WRTVDP Schrijft naar VDP-register. + Invoer: C = register, B = data + Verandert: AF,BC +&H013E RDVDP Lezen van S#0 van VDP. + Uitvoer: A = data +&H012D EXT WRTVDP Schrijft naar VDP-register. + Invoer: C = register, B = data + Verandert: AF,BC + +(EXT betekent dat de routine in het Extended ROM staat. Je +moet zo'n routine aanroepen door het adres in IX te laden en +daarna CALL &H015F te geven.) + +&H0131 EXT VDPSTA Lezen van statusregister van VDP. + Invoer: A = register (0-9) + Uitvoer: A = data + Wijzigt: F + +Het lezen van niet-statusregisters is niet mogelijk. Wel +wordt er door de BIOS routines een tabel bijgehouden van de +VDP registers in het systeem RAM. Deze tabel is alleen +betrouwbaar als de VDP registers alleen via de BIOS routines +worden beschreven, of als u er zelf voor zorgt dat u bij het +schrijven van een register de waarde in het RAM bijwerkt. +Dit verbetert vaak de samenwerking met andere programma's +(bijvoorbeeld MemMan TSR's). + +De inhoud van de VDP registers wordt door het BIOS op de +volgende plaatsen in het systeem RAM bijgehouden: + +R#0-R#7 &HF3DF-&HF3E6 +R#8-R#23 &HFFE7-&HFFF6 +R#25-R#27 &HFFFA-&HFFFC + +De commandoregisters R#32-R#46 worden niet (of in ieder +geval niet op deze manier) in het systeem RAM opgeslagen. +Dit is in principe ook onzin, omdat deze registers na het +uitvoeren van het commando hun oorsponkelijke waarde hebben +verloren. (N.B. Bij gebruik van de VDP door de SUB ROM +routines voor COPY e.d. worden de commando registers +uiteraard wel in het systeem RAM gezet, maar dit is voor ons +verder niet interessant.) + + +## V I A I / O P O O R T E N + +1) Direct + +Schrijf eerst de data en daarna het registernummer naar port +#1, waarbij bit 7 is gezet. Officieel moet de I/O poort uit +het ROM worden gelezen, maar onderstaande waardes gelden +altijd, en mogen dus gewoon gebruikt worden: + +port #0 I/O &H98 +port #1 I/O &H99 +port #2 I/O &H9A +port #3 I/O &H9B + +Het gaat dus volgens het volgende schema: (binair) + + MSB 7 6 5 4 3 2 1 0 LSB +Port #1 First Byte D7 D6 D5 D4 D3 D2 D1 D0 DATA + Second Byte 1 0 R5 R4 R3 R2 R1 R0 REGISTER # + + +In machinetaal ziet dit er zo uit: +``` + DI + LD A,100 + OUT (&H99),A + LD A,23+128 + OUT (&H99),A + EI +``` +Hier wordt de waarde 100 naar R#23 geschreven. Door 128 bij +het registernummer op te tellen wordt bit 7 gezet, waarmee +we de VDP vertellen dat hij het getal dat hij daarvoor had +ontvangen naar een register moet schrijven, waarvan het +nummer in de onderste zes bits staat. + +De interrupts moeten hierbij altijd uitstaan, omdat er +anders tussen de OUTs een interrupt kan optreden, waardoor +het misgaat omdat er in de interrupt meestal wel iets met de +VDP wordt gedaan. Als de interrupts al uit stonden kunt u de +DI en EI natuurlijk weglaten, de EI kan natuurlijk worden +weggelaten als de interrupts uit moeten blijven staan +(bijvoorbeeld omdat er nog een VDP register wordt +beschreven). + +Je zou dit natuurlijk ook in een subroutine kunnen zetten, +maar dat heeft weinig nut omdat het zo veel sneller gaat. + + +2) Indirect + +Zet eerst het registernummer in R#17, dat kan niet op de +indirekte manier. Schrijf daarna de data naar port #3. Dit +is vooral erg handig als je een reeks opeenlopende registers +wilt beschrijven (bijvoorbeeld de commando registers R#32 +t/m R#46). Als je namelijk AII (bit 7 van R#17, Auto +Increment Inhibit) op 0 zet, wordt R#17 automatisch +verhoogd. In schema gaat het als volgt: +``` + MSB 7 6 5 4 3 2 1 0 LSB +R#17 AII 0 R5 R4 R3 R2 R1 R0 REGISTER # +Port #3 First Byte D7 D6 D5 D4 D3 D2 D1 D0 DATA +Port #3 Second Byte D7 D6 D5 D4 D3 D2 D1 D0 DATA +... +Port #3 nth Byte D7 D6 D5 D4 D3 D2 D1 D0 DATA +``` + +Dit wordt vooral veel gebruikt bij het sturen van commando's +naar de VDP. De commandoregisters worden pas in deel 3 en 4 +behandeld, maar ik zal nu vast een stukje standaarcode +geven. We maken hier gebruik van de instructie OTIR van de +Z80, dat B bytes vanaf adres HL naar poort C stuurt. Stel we +willen de 15 waardes die achter COPY: staan naar de +commandoregisters sturen (R#32 t/m R#46): +``` + DI + LD A,32 + OUT (&H99),A + LD A,17+128 + OUT (&H99),A +``` +Hiermee zetten we het "beginregister" voor het indirect naar +de VDP schrijven op 32, omdat het AII bit gelijk is aan 0 +wordt dit registernummer automatisch verhoogd als we een +byte naar Port #3 schrijven. +``` + LD B,15 + LD C,&H9B ; LD BC,&H0F9B kan ook + LD HL,COPY + OTIR + . + . + . +COPY: DB 0,1,0,1,0,2,1,2,3,4,1,2,1,2,3 ; willekeurige data +``` + +Zoals we al eerder hebben gezien is het adres van Port #3 +gelijk aan &H9B. Met de OTIR sturen we de 15 waardes naar +register 32 t/m 46. + + +3) Palette Registers + +Voor het palet heeft de VDP paletteregisters P#0 t/m P#15, +die alleen indrect aan te sturen zijn. Het paletnummer moet +in R#16 staan, dit wordt automatisch verhoogd nadat het +paletregister is beschreven. Voor elk paletregister zijn +twee bytes nodig, waarvan slechts 9 bits worden gebruikt. 3 +voor rood, 3 voor blauw en 3 voor groen. Totaal geeft dat +2^9=512 kleuren. De databytes moeten naar Port #2 worden +geschreven. Wederom een schema: + +``` + MSB 7 6 5 4 3 2 1 0 LSB +R#16 0 0 0 0 C3 C2 C1 C0 paletnummer +Port #2 First Byte 0 R2 R1 R0 0 B2 B1 B0 data + ROOD BLAUW +Port #2 Second Byte 0 0 0 0 0 G2 G1 G0 data + GROEN +``` + +De waarde in R#16 wordt automatisch verhoogd, als je het +hele palet wilt invullen hoef je dus slechts eenmaal de +waarde 0 naar R#16 te schrijven en kun je daarna 32 bytes +naar Port #2 schrijven. De volgende standaardroutine +schrijft een willekeurig palet naar de VDP: +``` + DI + XOR A + OUT (&H99),A + LD A,16+128 + OUT (&H99),A ; P#0 selecteren + LD BC,&H209A ; 32 bytes naar &H9A + LD HL,PALET ; palet staat vanaf PALET + OTIR ; stuur palet uit +``` + +## S T A T U S R E G I S T E R S L E Z E N + +Als je de statusregisters van de VDP (S#0-S#9) wilt lezen +moet je eerst het registernummer in R#15 zetten. Vervolgens +moet je port #1 uitlezen. Hier het schema: +``` + MSB 7 6 5 4 3 2 1 0 LSB +R#15 0 0 0 0 S3 S2 S1 S0 STATREG # +Port #1 Read data D7 D6 D5 D4 D3 D2 D1 D0 DATA +``` +Omdat de interrupt routine in het BIOS zo snel mogelijk te +houden wordt er vanuit gegaan dat statusregister 0 altijd +geselecteerd is, er wordt dus simpelweg IN A,(&H99) gedaan +om S#0 te lezen (dit is nodig om te kijken of een interrupt +van de VDP afkomstig is on niet). De interrupts moeten +daarom bij het uitlezen van een statusregister altijd uit +staan, en S#0 moet weer geselecteerd zijn als de interrupts +weer aan worden gezet. In onderstaand voorbeeld wordt S#2 +uitgelezen in ML: +``` + DI + LD A,2 + OUT (&H99),A + LD A,15+128 + OUT (&H99),A ; S#2 selecteren + NOP + NOP ; wacht even + IN A,(&H99) + EX AF,AF + XOR A + OUT (&H99),A + LD A,15+128 + OUT (&H99),A ; selecteer S#0 voor BIOS + EI + EX AF,AF ; waarde S#2 staat nu in A +`` + +De twee NOPs zijn nodig om de VDP de tijd te geven om de +data klaar te zetten op Port #1. Er wordt twee keer EX AF,AF +gebruikt, zodat de waarde van het statusregister aan het +einde van het stukje code nog in A staat. + +Eventueel kan IN A,(&H99) als volgt worden vervangen om te +wachten totdat een bepaald bit (in het voorbeeld bit 0) van +het statusregister 0 is: +``` +WAIT: IN A,(&H99) + BIT 0,A + JP NZ,WAIT +``` +In dit geval is het natuurlijk niet nodig om het A register +te bewaren met EX AF,AF, eventueel kan een bepaalde actie +die moet worden uitgevoerd zodra het bit 0 is eerst worden +uitgevoerd, dus voordat S#0 weer wordt geselecteerd. Als de +interrupts maar uit staan! + + +## A A N S T U U R S N E L H E I D + +Hoewel dit nergens in het MSX2 Technical Handbook van ASCII +staat, kunnen er problemen ontstaan als de VDP te snel wordt +aangestuurd. Dit is afhankelijk van de afstand tussen de +processor en de VDP in de computer. Onderstaande manier van +de VDP aansturen is dan ook af te raden, omdat dit niet op +alle computers goed zal werken: +``` + DI + LD C,&H99 + LD D,0 + LD E,128+9 + OUT (C),D + OUT (C),E +``` +De OUTs worden hier te snel achter elkaar gegeven. +Vuistregel is om ongeveer zeven Z80-klokpulsen tussen twee +OUTs te wachten. Dit komt overeen met twee NOPjes of +bijvoorbeeld een LD A,x instructie. In bovenstaand +voorbeeld wordt de waarde 0 naar R#9 geschreven. Dit kan +beter als volgt gebeuren, zodat het op alle computers werkt: +``` + DI + XOR A + OUT (&H99),A + LD A,128+9 + OUT (&H99),A +``` +Extra voordelen hiervan zijn dat je veel minder registers +gebruikt, en dat het nog sneller is ook! Zorg er dus voor +dat bij het schrijven naar Port #0 t/m Port #3 altijd even +wordt gewacht tussen twee OUTs! De "snelheidswinst" die door +twee OUTs achter elkaar wordt gehaald is echt te +verwaarlozen, en bovendien geeft dit "troep op het beeld" +bij sommige computers! + + +## R 8 0 0 + +Nu verwacht u misschien problemen bij de turbo R, bij de +R800 duurt een LD A,x of twee NOPjes immers veel korter dan +bij de Z80. Maar dan onderschat u de mensen bij ASCII, die +natuurlijk rekening hebben gehouden met dit probleem. In de +R800 stand zorgt de S1990 er namelijk voor dat de R800 bij +elke OUT naar de VDP een bepaalde tijd moet wachten, die +overeen komt met de offici�le aanstuursnelheid van de VDP +zoals die door Yamaha wordt opgegeven. Het enige nadeel +hiervan is dat deze tijd iets langer is dan per se nodig. +Gelukkig is de R800 zo snel dat je daar verder weinig van +merkt. Het maakt in R800 stand dus niet uit hoe snel de data +naar de VDP wordt gestuurd, maar omdat de R800 toch moet +wachten heeft het weinig zin om de "twee OUTs direct achter +elkaar methode" toe te passen. + +Het is overigens niet zo (zoals in het begin van het turbo R +tijdperk werd beweerd) dat de VDP sneller is op de turbo R. +Hij is gewoon precies even snel. Het aansturen van de VDP +met OUTs gaat in R800 mode zelfs iets langzamer! VDP +routines (bij bijvoorbeeld Micro Cabin spellen zoals Xak +III) worden wel sneller op de R800, maar dat komt omdat het +rekenwerk dat aan vrijwel iedere VDP opdracht vooraf gaat +natuurlijk een stuk sneller gaat bij de R800. + + +## T E N S L O T T E + +Ik hoop dat ik veel trouwe lezers een plezier heb gedaan met +deze herhaling. Vooral in deze aflevering heb ik veel +veranderd, in de oorspronkelijke tekst werd er vrijwel niet +aan ML gedaan. + +Hier nog even een overzicht van de onderwerpen die in de VDP +cursus deel 1 t/m 9 zijn behandeld: + +1. VDP registers lezen/schrijven +2. Overzicht VDP registers en VRAM lezen/schrijven +3. Commandoregisters (1) +4. Commandoregisters (2) +5. Statusregisters +6. Sprites +7. Opslag schermen in VRAM (1) +8. Opslag schermen in VRAM (2) +9. Opslag schermen in VRAM (3) + +Vanaf deel 10 (dit deel staat op Sunrise Magazine #5) worden +praktijkvoorbeelden behandeld. Er is verder nog een VDP +cursus Extra, speciaal voor MSX2+. Dit deel zal uiteraard +ook worden herhaald. Ik zal verder nog een deel "Opslag +schermen in VRAM (4)" schrijven, waarin SCREEN 10 t/m 12 aan +bod komen. Op deze Sunrise Special ook de herhaling van deel +2. + +Tot de volgende keer! + +Stefan Boer \ No newline at end of file diff --git a/sunrise_special/2/vdp_cursus_2.md b/sunrise_special/2/vdp_cursus_2.md new file mode 100644 index 0000000..b1040e2 --- /dev/null +++ b/sunrise_special/2/vdp_cursus_2.md @@ -0,0 +1,455 @@ +# M S X 2 / 2 + V D P C U R S U S ( 2 ) + + +## I N L E I D I N G + +Dit is het tweede deel van de VDP cursus op herhaling. Deze +keer zal ik een overzicht geven van een groot aantal VDP +registers. Ze worden niet op volgorde van nummer behandeld, +maar in groepjes bij elkaar. + +De belangrijkste wijziging ten opzichte van de oude versie +is dat er nu bij het lezen/schrijven van VRAM meer aandacht +wordt besteed aan ML. + + +## M O D E R E G I S T E R S +``` + MSB 7 6 5 4 3 2 1 0 LSB +R#0 0 DG IE2 IE1 M5 M4 M3 0 Mode Register 0 +R#1 0 BL IE0 M1 M2 0 SI MAG Mode Register 1 +R#8 MS LP TP CB VR 0 SPD BW Mode Register 2 +R#9 LN 0 S1 S0 IL E0 NT DC Mode Register 3 + +R#0: DG : digitaliseren + IE2: 1 = interrupt van lichtpen of muis mogelijk + IE1: 1 = interrupt mogelijk bij bepaalde beeld- + lijn (zie R#19) +R#1: BL : scherm aan/uit (0=uit) + IE0: 1 = normale interrupt mogelijk + SI : 1 = sprite grootte 16x16, 0 = 8x8 + MA : 1 = vergrote sprites, 0 = normale sprites +``` +De schermmodi kunnen worden ingesteld met M1-M5: +``` + M5 M4 M3 M2 M1 +SCREEN 1 (G1) 0 0 0 0 0 +SCREEN 0 (T1) 0 0 0 0 1 (WIDTH 40) +SCREEN 3 (MC) 0 0 0 1 0 +SCREEN 2 (G2) 0 0 1 0 0 +SCREEN 4 (G3) 0 1 0 0 0 +SCREEN 0 (T2) 0 1 0 0 1 (WIDTH 80) +SCREEN 5 (G4) 0 1 1 0 0 +SCREEN 6 (G5) 1 0 0 0 0 +SCREEN 7 (G6) 1 0 1 0 0 +SCREEN 8 (G7) 1 1 1 0 0 +``` +De tekens tussen haakjes achter de schermmodi zijn de +offici�le benamingen. (T=TEXT, G=GRAPHIC, MC=MULTI COLOR) +``` +R#8: MS : 1 = color bus input / muis mogelijk + 0 = color bus output / geen muis mogelijk + LP : 1 = lichtpen mogelijk, 0 = geen lichtpen + TP : 1 = kleur 0 niet meer transparant + CB : 1 = color bus input, 0 = color bus output + VR : kies soort VRAM + 1 = 64K x 1 bit of 64K x 4 bits + 0 = 16K x 1 bit of 16K x 4 bits + SPD: 1 = sprites uit, 0 = sprites aan + BW : 1 = zwart/wit in 32 grijstinten, 0 = kleur +R#9: LN : Bepaal hoogte van scherm. 1=212, 0=192 + S0/1: Synchronisatiemode: + S1: S0: + 0 0 intern + 0 1 mix + 1 0 extern (digitize) + 1 1 niet + IL : 1 = interlace + EO : 1 = afwisselen even/oneven PAGE + NT : 0 = NTSC 60 Hz, 1 = PAL 50 Hz + DC : 1 = *DLCLK input, 0 = *DLCLK output +``` + +## T A B L E B A S E A D D R E S S R E G I S T E R S + +Deze adressen geven aan waar de diverse tabellen in het VRAM +beginnen. Dit komt overeen met BASE(n) in BASIC. +``` + MSB 7 6 5 4 3 2 1 0 LSB +R#2 0 A16 A15 A14 A13 A12 A11 A10 scherminfotabel +R#3 A13 A12 A11 A10 A9 A8 A7 A6 kleurtabel low +R#10 0 0 0 0 0 A16 A15 A14 kleurtabel high +R#4 0 0 A16 A15 A14 A13 A12 A11 patroontabel +R#5 A14 A13 A12 A11 A10 A9 A8 A7 sprite-info low +R#11 0 0 0 0 0 0 A16 A15 sprite-info high +R#6 0 0 A16 A15 A14 A13 A12 A11 sprite-patroon +``` +In BASIC kun je deze adressen opvragen met BASE(n). n moet +dan gelijk zijn aan vijf maal de screenmode plus: +0: scherminfo : SCREEN 0-4: patroonnummers + SCREEN 5-8: bitmapped +1: kleur : alleen SCREEN 0-4 (beh. WIDTH 40) +2: patroon : alleen SCREEN 0-4 +3: sprite-info : coordinaten e.d. +4: sprite-patroon : sprite$()="..." + +Voorbeeld: de sprite-info tabel van SCREEN 7 begint dus op +de waarde die in BASE(5*7+3) staat. + +Je kunt met behulp van deze registers in SCREEN 0-4 zeer +veel schermen tegelijk in het VRAM zetten, omdat die +schermen maximaal 16 kB per page nodig hebben, en je hebt +128 kB. Uitleg over hoe de beeldinformatie wordt opgeslagen +in deel 7 t/m 9. + +Je kunt aan de gegevens ook zien waarvan de BASE(n) waarden +een veelvoud moeten zijn. Als je je daaraan niet houdt, +volgt er een foutmelding. Bijvoorbeeld de spritepatroon- +tabel. Het laagste bit dat door R#6 wordt bepaald is A11. +Het moet dus een veelvoud zijn van 2^11 = 2048. + +Zie verder deel 7 t/m 9. + + +## K L E U R R E G I S T E R S +``` + MSB 7 6 5 4 3 2 1 0 LSB +R#7 TC3 TC2 TC1 TC0 BD3 BD2 BD1 BD0 Tekst/Achtergr +R#12 T23 T22 T21 T20 BC3 BC2 BC1 BC0 Blinkkleuren +R#13 ON3 ON2 ON1 ON0 OF3 OF2 OF1 OF0 Blinktijden + +TC3-TC0 : tekstkleur in T1 en T2 +BD3-BD0 : achtergrondkleur in alle schermmodi +T23-T20 : tekstkleur voor blink in T2 +BC3-BC0 : achtergrondkleur voor blink in T2 +ON3-ON0 : tijd voor blink-kleur +OF3-OF0 : tijd voor normale kleur +``` +Je kunt R#13 ook gebruiken om de PAGEs van SCREEN 5-8 +afwisseld weer te geven. Stel met SET PAGE de weergegeven +PAGE op 1 of 3, en zet dan de gewenste tijden in R#13. PAGE +1 en 0 (resp. 3 en 2) zullen dan beurtelings worden getoond. +Voorbeeld: SET PAGE 1 : VDP(14)=&H66 'page 0 en 1 worden nu +beurtelings getoond met een tussenpauze van ca. 1 seconde. + + +## U I T L E G B I J B L I N K M O D E + +Je kunt in SCREEN 0, WIDTH 80 (T2 mode) alternatieve scherm- +kleuren gebruiken. Er is hiervoor een speciale tabel +gereserveerd in het VRAM. Het beginadres daarvan staat in +BASE(1). In die tabel staat voor elke schermpositie 1 bit. +Is dat bit gelijk aan 1, dan wordt de alternatieve kleur +getoond. Is het bit gelijk aan 0, dan wordt de normale kleur +getoond. Eventueel kun je de alternatief gekleurde delen van +het scherm ook nog laten knipperen. De knippertijd moet in +R#13 worden gezet. Dat gaat in ongeveer 1/6 seconde +nauwkeurig. De hoogste vier bits bepalen de tijd voor de +alternatieve kleur, de laagste vier bits bepalen de tijd +voor de normale kleur. In R#12 (VDP(13)) staan de +alternatieve kleuren. De bovenste vier bits de voorgrond- en +de onderste vier bits de achtergrondkleur. Zet de waarde +&H10 in R#13 (VDP(14)) als je niet wilt knipperen, maar de +alternatieve kleur constant wilt tonen. + +De blinkertabel is als volgt ingedeeld: +BASE(1)+ 0: posities ( 0, 0)...( 7, 0) +BASE(1)+ 1: posities ( 8, 0)...(15, 0) +BASE(1)+ 9: posities (72, 0)...(79, 0) +BASE(1)+ 10: posities ( 0, 1)...( 7, 1) +BASE(1)+239: posities (72,23)...(79,23) + +Blinktijden (60 Hz, VDP(10)=0, NTSC, milliseconde): +Data: (hex) Tijd: (ms) Data: (hex) Tijd: (ms) +------------------------------------------------------------ +0 0 8 1335.1 +1 166.9 9 1501.9 +2 333.8 A 1668.8 +3 500.6 B 1835.7 +4 667.5 C 2002.6 +5 834.4 D 2169.5 +6 1001.3 E 2336.3 +7 1168.2 F 2503.2 +------------------------------------------------------------ + +Voorbeeld: je wilt de posities (12,3), (14,3) en (50,12) +laten knipperen met voorgrondkleur magenta (13) en achter- +grondkleur donkerblauw (4). De normale kleur moet 500.6 ms +getoond worden, de alternatieve kleur 166.9 ms. + +Eerst berekenen we de adressen: +14 \ 8 = 1 > Het adres wordt dus: BASE(1)+30+1 +14 MOD 8 = 6 > Het ene bitnummer wordt 7 - 6 = 1 en +12 MOD 8 = 4 > het andere bitnummer wordt 7 - 4 = 3, dus +3 * 10 = 30 > de te VPOKEn waarde is &B00001010 = 10 + +50 \ 8 = 6 > Het adres wordt dus: BASE(1)+120+6 +50 MOD 8 = 2 > Het bitnummer wordt 7 - 2 = 5, dus de te +12 * 10 = 120 > VPOKEn waarde is &B00100000 = 32 + +In de tabel vinden we voor de blinktijden de waardes 3 en 1. +13 is gelijk aan &HD. Dat lever totaal op: +VPOKE BASE(1)+31,10: VPOKE BASE(1)+126,32: VDP(13)=&HD4: +VDP(14)=&H13 + +N.B. Op Sunrise Special #2 staat een uitgebreid artikel over +een standaard ML routine voor de blinkmode en vier nieuwe +BASIC commando's (CMD BCOL, CMD BFIL, CMD BTIM en CMD BRES), +waarmee de blink mode eenvoudig vanuit BASIC te besturen is. + + +## C O L O R B U R S T R E G I S T E R S +``` + MSB 7 6 5 4 3 2 1 0 LSB +R#20 0 0 0 0 0 0 0 0 Color burst 1 +R#21 0 0 1 1 1 0 1 1 Color burst 2 +R#22 0 0 0 0 0 1 0 1 Color burst 3 +``` +Ik weet nog steeds niet waar deze registers voor dienen. Als +iemand het weet, graag even een briefje naar de Sunrise +postbus t.a.v. ondergetekende. Ik denk overigens dat deze +registers in het geheel geen nut hebben voor de programmeur, +het schrijven van willekeurige waardes naar deze registers +heeft namelijk geen enkel merkbaar effect. + +## D I S P L A Y R E G I S T E R S +``` + MSB 7 6 5 4 3 2 1 0 LSB +R#18 V3 V2 V1 V0 H3 H2 H1 H0 Display adjust +R#23 DO7 DO6 DO5 DO4 DO3 DO2 DO1 DO0 Display offset +R#19 IL7 IL6 IL5 IL4 IL3 IL2 IL1 IL0 Interrupt line +``` +R#18 werkt ongeveer net zo als SET ADJUST(dx,dy) in Basic. +Het bepaalt de positie van het beeld op het scherm. +LINKS: H=7...H=1 MIDDEN: H=0 RECHTS: H=15...H=8 +ONDER: V=8...V=15 MIDDEN: V=0 BOVEN: V=1...V=7 +Dit register wordt vaak op de MSX2 gebruikt om een horizon- +tale scroll te maken. Denk hierbij aan Space Manbow, +Golvellius 2, Super Cooks, Pennant Race 2. Je ziet dan een +happende rand. Op de MSX2+ wordt de scroll dan meestal +beter. + +Met R#23 (beter bekend als VDP(24)) kun je zeer eenvoudig +een verticale scroll maken op de MSX2. Een van de volgende +keren zal ik een programmavoorbeeld hiervan laten zien. De +waarde in VDP(24) geeft aan op welke hoogte de bovenste lijn +van het scherm zich bevindt. + +Met R#19 kun je aangeven bij welke beeldlijn de VDP een +interrupt moet geven. (Zie ook R#0). Je hebt dit register +nodig voor screensplits. Bij een screensplit kun je een +bepaalde actie (bijvoorbeeld een pagewissel, schermwissel, +kleurwissel, scrollen, etc.) laten uitvoeren, op het moment +dat de VDP een bepaalde beeldlijn naar het beeldscherm +stuurt. Ik zal hier nu verder niet op in gaan, een +screensplit zal bij de praktijkvoorbeelden (deel 10 en +verder van de VDP cursus) zeker aan bod komen. + + +## A C C E S R E G I S T E R S + +Deze registers gebruik je bij lezen/schrijven van VDP- +registers en VRAM. +``` + MSB 7 6 5 4 3 2 1 0 LSB +R#14 0 0 0 0 0 A16 A15 A14 VRAM Base +R#15 0 0 0 0 S3 S2 S1 S0 S# pointer +R#16 0 0 0 0 C3 C2 C1 C0 Color palette +R#17 AII 0 RS5 RS4 RS3 RS2 RS1 RS0 R# pointer +``` +Over het gebruik van R#15-17 heb ik in deel 1 al het een en +ander uitgelegd. Daarom hier alleen kort de werking: +R#15 Statusregister pointer. Schrijf het nummer van het te + lezen statusregister naar R#15. De data komt in Port + #1. +R#16 Color palette pointer. Schrijf het color palette + nummer naar R#16. Schrijf daarna de kleurdata naar + Port #2. Doe dat als volgt (binair): + 1e byte: 0 R1 R2 R0 0 B2 B1 B0 + 2e byte: 0 0 0 0 0 G2 G1 G0 + De waarde van R#16 wordt automatisch verhoogd, zodat + meerdere palet entries kunnen worden veranderd zonder + eerst het nummer naar R#16 te moeten schrijven. +R#17 Indirekte VDP-beschrijving. Schrijf het registernummer + naar R#17. Schrijf daarna de data die naar dat + register moet naar Port #3. Als je wilt dat het regis- + ternummer automatisch verhoogd wordt, moet je het AII + bit op 0 zetten. + +(Het schrijven naar Port #0 t/m Port #3 gebeurt met +OUT-instrukties. De I/O adressen voor Port #0 t/m Port #3 +zijn altijd &H98 t/m &H9B.) + + +## L E Z E N / S C H R I J V E N V R A M + +Om het VRAM te lezen/schrijven moet je de volgende procedure +volgen: + +1) Bankswitching. In principe is dit niet nodig, omdat +normaal gesproken altijd het normale VRAM is geselecteerd. +Sommige computers hebben 64 kB expansion VRAM, dit kan +gebruikt worden door bankswitching toe te passen. in R#45 +aan of je het VRAM (0) of het Expansion RAM (1) wilt +gebruiken. Plaats de overeenkomstige waarde in bit 6. + MSB 7 6 5 4 3 2 1 0 LSB +R#45 0 MXC MXD MXS DIY DIX EQ MAJ Argument Reg. +MXD = 0 betekent VRAM, 1 betekent Exp RAM + +2) Het VRAM adres kan vari�ren van 0-1FFFFH (128 kB). Plaats +de drie hoogste bits in R#14: + MSB 7 6 5 4 3 2 1 0 LSB +R#14 0 0 0 0 0 A16 A15 A14 VRAM Base +(Vanaf hier is het MSX1 compatible.) + +3) Schrijf de acht laagste bits naar Port #1. + MSB 7 6 5 4 3 2 1 0 LSB +Port #1 A7 A6 A5 A4 A3 A2 A1 A0 First Byte + +4) Schrijf de bits 8-13 naar Port #1. Bepaal lezen/ +schrijven met bit X. X=1: Schrijven, X=0: Lezen. + + MSB 7 6 5 4 3 2 1 0 LSB +Port #1 0 X A13 A12 A11 A10 A9 A8 Second Byte + +N.B. Bit 7 moet 0 zijn, hieraan kan de VDP zien dat de +waarde die hij zojuist ontvangen heeft niet naar een VDP +register moet (dan is bit 7 namelijk 1), maar dat het de +bits 0-7 van het adres zijn. Voor bit 6 en 7 geldt dus het +volgende: + +b7 b6 +1 0 VDP register schrijven +0 0 VRAM lezen +0 1 VRAM schrijven + +5) Lees of schrijf de data van/naar Port #0 (I/O poort +&H98). Het adres wordt automatisch verhoogd, dus je kunt +continu doorgaan met het lezen of schrijven van data. + +Het lezen/schrijven van VRAM kan weer op drie manieren, +namelijk in BASIC, in machinetaal via BIOS en in machinetaal +door rechtstreeks de VDP aan te sturen met IN en OUT. + +In BASIC gaat het uiteraard gewoon met VPOKE, de BASIC +interpreter zorgt voor de rest. In het BIOS zijn de volgende +routines aanwezig voor het lezen/schrijven van VRAM: + + MSX2: + +&H016E NSETRD Stel VDP in om VRAM te lezen vanaf adres + in HL. Na het aanroepen van deze routine + kan de data uit Port #0 worden gelezen. +&H0171 NSTWRT Stel VDP in om VRAM te schrijven vanaf + adres in HL. Na het aanroepen van deze + routine kan de data naar Port #0 worden + geschreven. +&H0174 NRDVRM Lees VRAM. HL=adres, A=data, wijzigt F. +&H0177 NWRVRM Schrijf VRAM. HL=adres, A=data, + wijzigt AF. +N.B. NRDVRM en NWRVRM gebruiken NSETRD en NSTWRT. + + MSX1/2: +&H004A RDVRM Zie NRDVRM, alleen SCREEN 0-4! +&H004D WRTVRM Zie NWRVRM, alleen SCREEN 0-4! +&H0050 SETRD Zie NSETRD, alleen SCREEN 0-4! +&H0053 SETWRT Zie NSTWRT, alleen SCREEN 0-4! + +(De hierboven genoemde routines zijn gemaakt voor de MSX1, +en kunnen daarom alleen adressen tussen 0 en 16383 aan. Dit +is in SCREEN 0-4 geen bezwaar, maar in SCREEN 5-12 wel. Op +een MSX2 programma gewoon altijd NRDVRM, NWRVRM, NSETRD en +NSTWRT gebruiken, ook in SCREEN 0-4. RDVRM en WRTVRM +gebruiken SETRD en SETWRT.) + +0056H FILVRM Vult blok VRAM vanaf HL met lengte BC met + waarde A. Wijzigt: AF,BC. +0059H LDIRMV Kopieert blok VRAM->RAM. HL=bron, DE=doel, + BC=lengte. Wijzigt: alle. +005CH LDIRVM Kopieert blok RAM->VRAM. Zie LDIRMV +016BH BIGFIL Doet hetzelfde als FILVRM. Het verschil is + dat FILVRM bij SCREEN 0-3 net doet alsof er + maar 16 kB, en BIGFIL niet. + +Soortgelijke routines zijn ook in het SUBROM aanwezig, maar +aangezien het aanroepen daarvan alleen maar extra tijd in +beslag neemt laat ik dat hier achterwege. + +Nu rechtstreeks in ML. Ik geef hier de routines NSTWRT en +NSETRD. Deze routines zijn praktisch gelijk aan de routines +in het MAIN ROM, die kunt u dus rustig gebruiken. Deze +routines zijn dan ook vooral leerzaam! + +``` +; VRAM routines door Stefan Boer +; VDP cursus op herhaling deel 2 +; Sunrise Special #2 +; Door Stefan Boer +; (c) Sunrise 1992 + +; SETWRT +; Zet VDP klaar om naar VRAM te schrijven +; In: HL: bit 0-15 van adres +; C : bit 16 van adres + +SETWRT: LD A,H + RES 7,A + SET 6,A ; 0 1 is VRAM schrijven + JP RDWRT + +; SETRD +; Zet VDP klaar om uit VRAM te lezen +; In: HL: bit 0-15 van adres +; C: bit 16 van adres + +SETRD: LD A,H + AND &B00111111 ; 0 0 is VRAM lezen + +; Dit gedeelte is voor beide routines hetzelfde + +RDWRT: PUSH AF ; deze byte moet pas als + ; laatste naar Port #1 + LD A,C ; bit 16 van adres + AND 1 ; alleen bit 0 + LD C,A + LD A,H + AND &HC0 ; alleen bit 6 en 7 + ; (bit 14 en 15 van adres) + OR C ; bit 16 van adres erbij + RLCA + RLCA ; schuif bit 0, 6 en 7 naar + ; bit 0, 1 en 2 + DI + OUT (&H99),A + LD A,14+128 + OUT (&H99),A ; schrijf bit 14-16 van adres + ; naar R#14 + LD A,L ; bit 0-7 van adres + OUT (&H99),A ; naar Port #1 + POP AF ; bit 8-13 van adres, plus VDP + ; instructie + OUT (&H99),A ; naar Port #1 + EI + RET + +; data kan nu worden gelezen/geschreven via Port #0 (&H98) +``` +Deze routine spreekt voor zichzelf, u kunt de eerder +omschreven standaardprocedure hierin herkennen. + + +## T E N S L O T T E + +Met vragen over de VDP cursus kunt u natuurlijk altijd bij +mij terecht, net als met alle andere programmeervragen +overigens. Schrijf een briefje naar de Sunrise postbus, +t.a.v. ondergetekende. + +Op de volgende Sunrise Special zullen deel 3 en 4 van de VDP +cursus worden herhaald, daarin worden de commando registers +van de VDP behandeld. Hiermee kunt u zelf COPY's, LINEs, +etc. in machinetaal programmeren! + +Tot de volgende keer! + +Stefan Boer \ No newline at end of file diff --git a/sunrise_special/3/de_archeologie_van_de_msx.md b/sunrise_special/3/de_archeologie_van_de_msx.md new file mode 100644 index 0000000..6e3d3e6 --- /dev/null +++ b/sunrise_special/3/de_archeologie_van_de_msx.md @@ -0,0 +1,222 @@ +# D E A R C H E O L O G I E V A N D E M S X + + +Ofwel: waarom een vooruitziende blik achteraf beter was +geweest + +## I N L E I D I N G + +De tegenwoordige MSX2, MSX2+ of turbo R computers lijken +maar in weinig opzichten op hun MSX1-voorgangers van bijna +tien jaar geleden. De vroege MSX1 computers waren ontworpen +om vooral zo goedkoop mogelijk te zijn, en maakten dus +uitsluitend gebruik van goedkope standaardcomponenten, die +goed verkrijgbaar waren. De belangrijkste (LSI) componenten +waren: + +Type Taken Fabrikant(en) +------------------------------------------------------------ +Z80A processor Zilog, SGS, etc. +AY-3-8910 geluid, joystickpoorten General Instruments +8255 PPI toetsenbord, slotselectie Intel + cassette, diverse led's +9918A VDP display Texas Instruments + +Voor de rest kon gebruik gemaakt worden van standaard +(LS)TTL-, RAM- en EPROM IC's, aangevuld met wat ander spul +(zoals weerstanden, condensatoren, etc.) zodat een ervaren +hobbyist in principe zijn eigen MSX1 had kunnen bouwen met +componenten die bijna iedere electronicazaak kon leveren. + +Hoewel de gebruikte LSI-componenten niet erg duur waren, +bleken ze toch duur genoeg om er zo weinig mogelijk van te +gebruiken, hoewel bijvoorbeeld een extra 8255 de hardware +eenvoudiger had gehouden en de prestaties had verbeterd. Zo +is er bijvoorbeeld tussen de joystickpoorten en de 8910 +extra hardware nodig om tussen de twee joysticks (of wat er +ook aan die poorten zit) te schakelen, domweg omdat er +onvoldoende I/O lijnen beschikbaar zijn. + +Het lijkt er wel op of die tweede joystickpoort pas in een +later stadium aan de standaard is toegevoegd, en hetzelfde +kun je zeggen van de printerpoort, die op veel vroege +MSX-computers ontbrak. (Philips heeft ooit eens een +cartridge uitgebracht met alleen een printeraansluiting +erop!) + + +##H E T G E H E U G E N - P R O B L E E M + +De Z80 kan helaas niet meer dan 64 kB aan geheugen +adresseren, en dat was zelfs toendertijd te weinig, vooral +omdat er naast een verplichte BASIC-interpreter ook nog +software in cartridges moest kunnen lopen, en aan het toen +nog toekomstige MSX-DOS zal men ook wel gedacht hebben. + +Dit probleem is - zoals iedereen wel zal weten - opgelost +door de PPI-poort op 0A8h te gebruiken om voor de selectie +van de geheugenslots te dienen. Omdat we vier pagina's +moeten schakelen, en dat in een enkel byte moeten kunnen +doen, beperkt dat ons tot 2 bits per pagina, en dus een +maximum van vier slots. Dit lijkt het adresseerbare geheugen +uit te breiden to 4 x 64 = 256 kB, maar schijn bedriegt: ten +eerste mag pagina 3 nooit worden weggeschakeld, omdat daar +de systeemvariabelen in zitten en (meestal en hopelijk) de +stack, en ten tweede omdat het wegschakelen van pagina 0 de +BIOS onbereikbaar maakt, tenzij je ervoor zorgt dat er in +die pagina ook slotselectieroutines aanwezig zijn. (MSX-DOS +doet dit, maar daarover later meer.) + + +##H E T S E C U N D A I R E S L O T R E G I S T E R + +Achteraf gezien zal het dan ook niemand verbazen dat dit te +weinig bleek, maar wat wel verbazend is, is de manier waarop +men het heeft opgelost: het secundaire slotselectieregister +op 0FFFFh! + +Op zich is het natuurlijk al vreemd om een memory-mapped +register te gebruiken als er nog voldoende ongebruikte I/O +adressen zijn, maar dat kun je hoogstens een +schoonheidsfoutje noemen. Nee, waar het echte probleem ligt +is het feit dat ieder geâxpandeerd slot een eigen, +afzonderlijk slotselectie-register op 0FFFFh heeft! Dit feit +en wat de consequenties hiervan zijn realiseren maar heel +weinig mensen zich ten volle, dus laat ik ze hier op een +rijtje zetten: + +In pagina 3 zit een deel van de slotselectieroutines +(behalve voor ENASLT), en om een goede reden: als we van +(primair) slot veranderen is dat de enige pagina waarvan we +zeker weten dat hij op z'n plaats blijft na het schakelen. +Het ongelukkige van het secundaire slotregister op 0FFFFh +zit hem hierin, dat we juist pagina 3 moeten wegschakelen om +het secundaire slotregister te kunnen bereiken, waardoor een +secundaire slots selecteren nogal omslachtig wordt (de +stappen met een * gebeuren in pagina 3): + +1 - Schakel het gewenste primaire slot in, maar op pagina 3 +2 - Lees FFFF, complementeer, en onthoud de waarde +3 - Bereken de nieuwe waarde, en schrijf naar FFFF +4 - Herstel primair slot (situatie als voor 1) +5 - Bereken nieuw primair slot op de gewenste pagina +6* - Schrijf primair slotregister +7* - De gewenste actie (lezen, schrijven of CALLen) +8* - Herstel primair slotregister (situatie als voor 1) +9 - Schakel primair slot als bij 1 +10 - Schrijf oude waarde (uit 2) terug naar FFFF +11 - Herstel primair slotregister (situatie als voor 1) + + +Voor ongeâxpandeerde slots gaat 't simpeler: + +1 - Bereken nieuw primair slot op de gewenste pagina +2* - Schrijf primair slotregister +3* - De gewenste actie (lezen, schrijven of CALLen) +4* - Herstel primair slotregister (situatie als voor 1) + + +##D E C O N S E Q U E N T I E S + +Die ingewikkelde secundaire slotselectie is niet zonder +gevolgen. Zo moet iedere slotselectieroutine heen en weer +hinken tussen pagina 3 en (meestal) 0, terwijl het heel +handig (en een stuk sneller) zou zijn als we de complete +routine in pagina 3 kwijt zouden kunnen. MSX-DOS heeft +hetzelfde probleem, en heeft het leeuwendeel van de routines +in pagina 3 zitten, maar een deel zit verplicht in pagina 0. + +Een tweede gevolg is dat binnen een geâxpandeerd slot geen +CALSLT ed. gedaan kan worden naar pagina 0, of het moest via +aan omweg zijn! Dit kan uiterst onaangename consequenties +hebben voor computers met RAM en SUBROM in hetzelfde +geâxpandeerde slot, of (erger nog!) met een geâxpandeerd +slot 0. In het eerste geval moet een omweg via de BIOS (de +routine EXTROM) gemaakt worden, wat lastig wordt gemaakt +door het feit dat CALSLT ook het IX-register gebruikt. + +Dus waarom hebben ze het zichzelf zo ingewikkeld gemaakt? +Een deel van het antwoord ligt in het feit dat men +secundaire sloten herkent doordat bij teruglezen de waarde +wordt gecomplementeerd. Als men van dit gemak had afgezien - +de RAM en ROM check bij het opstarten van de computer wordt +dan iets ingewikkelder - dan hadden de secundaire +slotselectie registers write-only kunnen worden uitgevoerd. +In dat geval hoefde de hardware rond die registers er niet +op te letten of het desbetreffende primaire slot is +ingeschakeld, en bovendien kon de hardware voor het +teruglezen vervallen. (Het leuke is namelijk dat niet alleen +alle in het systeem aanwezige secundaire +slotselectieregisters beschreven worden, maar ook het gewone +RAM op 0FFFFh, zodat teruglezen nog steeds zonder meer +mogelijk is!) + +Dus ten koste van iets ingewikkelder software kan de +hardware eenvoudiger en bovendien vervallen dan bijna alle +bovenstaande bezwaren! (Naar het secundaire slotregister kan +dan nl. altijd geschreven worden, ook vanuit pagina 3. +Secundaire slotselectie wordt dus veel eenvoudiger.) Een +onbegrijpelijke misser! Je moet hier wel de conlusie uit +trekken dat het secundaire slot een late en weinig +doordachte toevoeging aan het MSX-systeem is. + + + +##H E T I N T E R R U P T S Y S T E E M + +Ook het interruptsysteem draagt de sporen van spaarzaam +denken. Interrupts veroorzaken altijd een sprong naar adres +38h, wat tot gevolg heeft dat daar natuurlijk altijd iets +aanwezig moet zijn om de interrupts af te handelen. (En er +moeten ook slotselectieroutines aanwezig zijn!) Deze +interrupt wordt altijd in de BIOS afgehandeld voor hij de zo +bekende hooks op FD9A en FD9F passeert. Dit heeft tot gevolg +dat een echt snelle interruptafhandeling niet mogelijk is, +zeker in DOS, waar er nog een extra interslot-call aan te +pas moet komen. + +Nvdr. BIOS wegschakelen en zelf iets op 38h zetten +misschien? + +Dat vaste interruptadres veroorzaakt bovendien nogal eens +problemen met CP/M debuggers, omdat adres 38h vaak door die +programma's wordt gebruikt. Beter ware het geweest om met +behulp van een PIC (priority interrupt controller) zoals de +8259 van Intel interrupt-vectoring te verzorgen, iets wat +nauwelijks extra kosten met zich had meegebracht, maar het +systeem wel een stuk sneller en flexibeler had gemaakt. + + +##D E V I C E S + +Aan de andere kant is het vreemd dat juist een doordacht +systeem als het device-systeem op de MSX nooit gebruikt +wordt; iets dat waarschijnlijk alleen toe te schrijven is +aan gebrek aan informatie (hoewel gebrek aan devices +natuurlijk ook kan). Om vooral geen slapende honden wakker +te maken zal ik volstaan met te zeggen dat dit (onder +andere) gaat via de hook B.EXT (FFCA), een hook die ook door +MemMan wordt gebruikt, hoewel deze beslist geen device is! +Buiten de devices die standaard in BASIC zitten (CRT: GRP: +CAS: LPT:) kunnen RS232-uitbreidingen (COM:) hiermee ook +worden gebruikt. + + +##C O N C L U S I E + +Bij het uitdenken van het MSX-systeem is goed nagedacht, +maar er zijn ook blunders gemaakt. Iedere computer is +natuurlijk een compromis tussen wensen en kosten, en +persoonlijk verbaast het mij dat het systeem telkens kon +worden uitgebreid zonder dat de compatibiliteit tussen de +systemen in belangrijke mate verloren ging. + +Wat betreft het secundaire slot systeem kun je je afvragen +of alle programmeurs wel precies weten hoe het werkt. Alle +Philips MSX2 computers hebben het RAM in het geâxpandeerde +slot 3 zitten, wat inhoudt dat het secundaire slotregister +altijd bereikbaar is. Programma's die rucksichtslos op FFFF +lezen of schrijven zullen op die computers wel werken, maar +kunnen op andere voor grote problemen zorgen. + +Robert Amesz diff --git a/sunrise_special/3/de_programmeertaal_c_deel_3.md b/sunrise_special/3/de_programmeertaal_c_deel_3.md new file mode 100644 index 0000000..db181cd --- /dev/null +++ b/sunrise_special/3/de_programmeertaal_c_deel_3.md @@ -0,0 +1,616 @@ +# D E P R O G R A M M E E R T A A L C - D E E L 3 + +## I N L E I D I N G + +Voor BASIC programmeurs is het gebruik van strings net zo +gemakkelijk als getallen: BASIC zoekt zelf wel uit hoe lang +strings zijn en waar ze in het geheugen terecht moeten +komen. PASCAL programmeurs hebben het wat moeilijker, +aangezien PASCAL eigenlijk geen strings kent (alleen ARRAYS +OF CHAR). In Turbo Pascal hebben ze dit probleem opgelost +door een van ARRAY OF CHAR afgeleid type, de STRING (hoe +verzinnen ze het, he?) te introduceren. Wel moet nog steeds +de maximale lengte worden gespecificeerd. + +Wat dat betreft lijkt C wel op Turbo Pascal, alleen zijn er +wat andere conventies wat betreft het gebruik van strings. +Strings in C zijn zo verweven met array's en pointers, dat +het zinloos zou zijn te proberen deze dingen los van elkaar +te behandelen. Maar om te beginnen zullen we moeten weten +hoe we moeten werken met array's in C. + + +## D E A R R A Y + +Een array is een rij variabelen van hetzelfde type, die elk +afzonderlijk kunnen worden aangesproken door middel van een +index. (Onthoud dit woord; het zal nog vaak gebruikt +worden!) Een array laat zich nog het best vergelijken met +een rij huizen, die allemaal identiek zijn. Als je naar een +bepaald huis in de rij wilt verwijzen zul je naast de +straatnaam (de naam van het array) ook het huisnummer moeten +gebruiken (de index). Ook in C is de index een getal. + +Om een array binnen C te declareren gaan we bijna hetzelfde +te werk als bij gewone variabelen. Zo algemeen mogelijk +geformuleerd: + + []; + +Hierbij is de al aan ons bekende datatypen (int, char +enz.), is de naam van het array en is het +aantal elementen van het array. Met + + int getallen[10]; + +creâren we dus een array 'getallen', bestaande uit 10 int's. +Met + + char buffer[80]; + +maken we een array 'buffer' van 80 char's. In C is de +laagste index altijd 0, en in bovenstaand voorbeeld is de +hoogste index 79. Dan hebben we totaal 80 elementen. Dus in +een array van N elementen loopt de index van 0 t/m N-1. LET +HIER GOED OP! In C wordt niet gecontroleerd of de index die +we gebruiken binnen deze grenzen valt, en dit kan tot zeer +venijnige bug's leiden, vooral als we iets in zo'n +niet-bestaand element willen opslaan! + +Overigens, de vierkante haakjes slaan alleen op de naam die +er direkt voor staat. Met + + int veel[40], enkel; + +declareren we dus een array 'veel' met 40 int's en een +gewone int-variabele, 'enkel'. +Een element uit een array gebruiken in een uitdrukking kan +als volgt: + + [] + +De is een gewone uitdrukking, en het is uiteraard +geen bezwaar als daarin ook weer elementen van een array +worden gebruikt. De volgende uitdrukkingen in C zijn dus +allemaal correct (ervan uitgaande dat de gebruikte +variabelen zijn gedeclareerd): + + buffer[0] + + getallen[x] + + getallen[x-1] + + buffer[getallen[x-1] + 1] + +Een en andere kan zo ingewikkeld worden als de +omstandigheden vereisen, zolang de index maar binnen de +juiste grenzen valt. Verwijzingen naar elementen mogen +overal gebruikt worden als gewone variabelen. Dus met + + getallen[x+1] = getallen[x] * 2; + +heeft C geen enkele moeite. + + +## P O I N T E R S + +Verwant met de array (nauwer zelfs dan je op het eerste +gezicht zou denken) is de pointer. Een pointer is een +variabele die 'wijst' naar een andere variabele. (Vandaar +pointer, want 'to point' is 'wijzen naar'). Om de variabele +waarnaar zo'n pointer wijst aan te kunnen spreken, of - +omgekeerd - van een variabele de verwijzing (d.w.z. het +adres) op te vragen zijn er in C een tweetal operatoren, +resp. de '*' en de '&'. Maar laten eerst eens beginnen met +het declareren van een pointer. Dit doen we met: + + *; + +Hiermee wordt dus een pointer gecreeerd die naar variabelen +van wijst. Een voorbeeld: met + + int *intptr; + +krijgen we een pointer 'intptr' die naar variabelen van het +type int wijst. Het sterretje heeft alleen betrekking op de +naam die er direkt achter staat. De declaratie + + int *intptr, x; + +creeert dus een gewone int-variabele 'x', en een +pointer-naar-int 'intptr'. We kunnen dus 'intptr' naar 'x' +laten wijzen! Dit kan met de '&' operator, die het adres van +een variabele levert. Met + + intptr = &x; + +wijst 'intptr' dus naar 'x'. Wil dit enig nut hebben dan +moeten we iets met die verwijzing kunnen doen. Met de '*' +operator krijgen we toegang tot de variabele waarnaar de +pointer wijst. Na + + intptr = &x; + *intptr = 3; + +zal 'x' dus de waarde 3 hebben gekregen. Dit is misschien +een beetje verwarrend, omdat we de '*' ook voor +vermenigvuldiging wordt gebruikt. Bij een vermenigvuldiging +heeft de '*' twee waarden nodig (en is dus een binaire +operator) en als verwijzing slechts 1 (een unaire operator). +Vergelijk dit bijvoorbeeld met de '-' operator, die zowel +'negatief maken' (unair) als 'aftrekken' (binair) betekent. +Omdat het vermenigvuldigen van pointers geen zinvolle +bezigheid is, kan er eigenlijk geen verwarring ontstaan. + +We kunnen ook naar een arrayelement wijzen. Dus met + + int getallen[10], *getal; + +declareren we een int-array 'getallen' en een +pointer-naar-int 'getal', waarna we met + + getal = &getallen[5]; + +'getal' naar het zesde (!) element van het array 'getallen' +zal wijzen. In sommige gevallen kan het echter nog simpeler +als we in element 0 - het eerste element van het array - +zijn geinteresseerd: + + getal = &getallen[0]; + +en + + getal = getallen; + +doen namelijk precies hetzelfde. Als we namelijk in C een +array declareren gebeuren er twee dingen: ten eerste wordt +er ruimte gereserveerd voor de elementen van het array. +Vervolgens wordt de pointer naar element 0 gekoppeld aan de +naam van het array. Een array is dus een bijzonder soort +pointer, maar dan een pointer die niet van waarde kan +veranderen! (Proberen we dit toch te doen dan volgt +(meestal) de wat cryptische foutboodschap: "Must be lvalue" +of: "Can't be rvalue". Dit is nog overgebleven uit de vroege +jaren van de taal C, en heeft te maken met de interne opslag +van informatie in de compiler zelf.) + +De slimmeriken onder ons zullen zich nu afvragen: "Als een +array een bijzonder soort pointer is, kunnen we dan pointers +net zo gebruiken als array's?" Het antwoord hierop luidt: +ja! De vierkante haken zijn eigenlijk niets anders dan de +zoveelste operator in C, maar dan eentje die - net als de +unaire '*' operator - alleen met pointers werkt. + +Een bijzonder geval is als een pointer NERGENS naar wijst. +Hiermee wordt niet bedoeld: naar een niet-bestaande +variabele, maar echt naar niets. Hiervoor is in STDIO.H de +waarde NULL gedefinieerd, en we kunnen met bijvoorbeeld + + getal = NULL + +de pointervariabele getal 'nergens' naar laten wijzen, en +met + + getal == NULL + +of + + getal != NULL + +kan getest worden of dit wel, resp. niet zo is. Het gebruik +van NULL berust in feite op een afspraak, en is zeer nuttig +in bepaalde algorithmen. Overigens zijn de '==' en de '!=' +operatoren de enige zinvolle vergelijkingsoperatoren voor +pointers. Men noemt twee pointers gelijk als ze naar +dezelfde variabele wijzen, of allebei NULL zijn. Pointers +kunnen natuurlijk eigenlijk alleen vergeleken worden als ze +ook naar hetzelfde type wijzen, als zijn er maar weinig +compilers die dit testen. Alleen NULL mag altijd gebruikt +worden, ongeacht het type waar de pointer naar wijst. + +Met pointers kan in zeer beperkte mate worden gerekend, en +dan alleen nog als pointers naar elementen van array's +wijzen. Kijk eens naar het volgende stukje C: + + int getallen[20], *ptr1, *ptr2; + ptr1 = &getallen[5]; + ptr2 = &getallen[10]; + +hierna doet + + *(ptr1 + 1) + +hetzelfde als + + getallen[6] + +En + + *(ptr1 + 3) + +komt overeen met + + getallen[8] + +Tenslotte, de uitdrukking + + ptr2 - ptr1 + +moet de waarde 5 opleveren. De meest gebruikte operator bij +pointers is echter de '++'. Na gebruik hiervan zal een +pointer naar het volgende element in het array wijzen, en in +een lus wordt dit zeer vaak gebruikt om de elementen een +voor een af te lopen. Dit is vaak handiger en bijna altijd +sneller dan met een index werken, al ziet het er voor niet +C-programmeurs soms wat onoverzichtelijk uit. + + +## S T R I N G S + +Tot nu toe is het een 'zware' aflevering geweest, maar +daaraan viel niet te ontkomen. Wees getroost: wie het tot nu +toe allemaal begrepen heeft zal de rest van de cursus ook +begrijpen. + +Strings in C zijn gelukkig heel simpel: het zijn gewoon +array's van het type char. De eerste letter van de string +vind je in element 0, de tweede in element 1, enzovoort. De +lengte van een string wordt dus nergens opgeslagen, in +plaats daarvan wordt na het laatste karakter een 0 +opgeslagen. Dit wordt een 'sentinel' (wachtpost) genoemd, en +zegt ons zoiets als: "Halt! Einde string." Dit houdt tevens +in dat we het array 1 groter moeten maken dan de maximum +lengte van de string, anders past het niet. + +Een andere consequentie is dat 0 nooit deel mag uitmaken van +de string, maar omdat strings eigenlijk bedoeld zijn voor +tekst is dit niet echt een probleem. + +In C kunnen we niet met hele array's (en dus ook strings) +tegelijk werken, in plaats daarvan gebruiken we pointers om +naar deze array's te verwijzen. De standaardbibliotheek kent +meer dan tien functie's die uitsluitend op strings +betrekking hebben, en strings kom je ook in veel I/O +routines tegen. In al die routines maakt men dus gebruik van +pointers, en de functie-return is meestal ook een pointer. + +## P R O G R A M M A V O O R B E E L D D E S O U N D E X C O D E + +In de Verenigde Staten zijn in de loop der tijden een groot +aantal volkstellingen gehouden, met het doel een beetje +overzicht te houden op de groeiende bevolking van dit land. +Vooral in het verleden was een groot percentage van de +mensen analfabeet, en veel mensen konden hun eigen naam +zelfs niet schrijven. + +Dit leidde ertoe dat ook de spelling van die namen niet +bekend was, en ambtenaren moesten vaak ter plekke zelf maar +verzinnen hoe een naam gespeld moest worden. Hierdoor waren +analfabeten vaak onder verschillende namen bij officiâle +instanties bekend. + +De ambtenaren van het volkstellingsbureau losten dit +probleem grotendeels op door voor namen een coderingsmethode +te verzinnen die voor namen met ongeveer dezelfde uitspraak +dezelfde code opleverde. Hierdoor was het mogelijk geworden +in bestanden namen te achterhalen zonder dat de precieze +spelling bekend hoefde te zijn. + +Deze coderingsmethode is vrij simpel, en laat zich +uitstekend tot een klein C-programmaatje maken. De +toepassingsmogelijkheden zijn legio, en is overal inzetbaar +waar we naar namen of woorden zoeken waarvan we de precieze +spelling niet kennen. + +De eerste letter van de code wordt gewoon uit de naam +overgenomen. Alle vorgende letters worden in klassen +verdeeld. Letters van klasse 0 (klinkers en bijna-klinkers) +worden genegeerd, andere klassen (1 t/m 6) worden gewoon als +nummer aan de code toegevoegd. Indien er twee of meer +letters van dezelfde klasse direkt achter elkaar staan, +wordt het nummer maar 1 keer toegevoegd. De totale code +wordt na vierde karakter afgekapt, of met nullen tot vier +karakters aangevuld. Om een voorbeeld te geven: zowel "jan" +als "johan" hebben de code "J500", "scheur" en "sguer" +hebben de code "S250". +``` + #include + + #define STRLEN 80 + + char naam[STRLEN]; + + char code[5]; + + char *soundex(src, dst) + char *src, *dst; + { + unsigned cur_len; + int alfa_pos; + char new_code, old_code, *old_dst; + + /* Onthoud begin van dst */ + old_dst = dst; + + cur_len = 0; + + /* Als string niet leeg is... */ + if (*src) { + + /* Neem eerste letter over */ + *dst++ = toupper(*src++); + cur_len++; + old_code = ' '; + + /* Doe tot codelengte = 4, of string ten einde */ + while (*src && (cur_len < 4)) { + + /* Bereken positie in het alfabet */ + alfa_pos = toupper(*src++) - 'A'; + + /* Als het een letter betreft, maak code */ + if ((alfa_pos >= 0) && (alfa_pos <= 25)) { + new_code="01230120022455012623010202"[alfa_pos]; + + /* indien code niet '0' en niet dubbel, voeg toe */ + if ((new_code != '0') && (new_code != old_code)) { + *dst++ = new_code; + cur_len++; + } /* if ((new_code... */ + old_code = new_code; + } /* if ((alfa_pos... */ + } /* while */ + } /* if (*src) */ + + /* Vul aan tot 4 karakters met '0' */ + while (++cur_len <= 4) *dst++ = '0'; + + /* Sluit de string af */ + *dst = '\0'; + + /* Geef originele pointer terug */ + return old_dst; + + } /* soundex */ + + main() + { + printf("\n\nBereken soundex-code\n\n"); + + while (TRUE) { + printf("Geef te coderen naam: "); + gets(naam, STRLEN); + + if ((*naam == '\n') (*naam == '\0') + (*naam == ' ')) + break; + + printf("\nDe soundex-code is: %s\n\n", + soundex(naam, code)); + } /* while */ + + printf("\n\nEinde programma\n\n"); + } +``` + +Na het doorlezen van bovenstaande listing zal menigeen met +een groot aantal vragen zitten. Laten we, net als de +computer, bij 'main' beginnen: + +Om te beginnen de + + while (TRUE) + +In "STDIO.H" wordt de constante TRUE ('waar') gedefinieerd. +Deze heeft in de meeste systemen de waarde 1, maar is in +ieder geval niet 0. De tegenhanger hiervan, FALSE +('onwaar'), is wel 0. Deze constanten worden gebruikt waar +we willen aangeven dat we logische waarden gebruiken. (In +tegenstelling tot PASCAL kent C geen speciaal logisch type.) +Deze constanten zijn alleen bedoeld om de leesbaarheid van +het programma te verbeteren. + +Betekent dit dat de 'while' lus eeuwig wordt doorlopen? Nou, +niet echt. In deze lus is gebruikt gemaakt van een +ontnappingsmogelijkheid die C ons biedt, namelijk het +'break' statement. Als dit wordt uitgevoerd springen we de +lus uit, naar het eerste statement na de lus. Deze 'break' +is ook in alle andere lussen bruikbaar. + +Dit 'break' statement is hier toegepast binnen een 'if' +statement. Hier kunnen we meteen zien hoe we met +karakterconstanten kunnen werken: gewoon tussen '' zetten. +Net als de strings die tussen "" staan kunnen we bijzondere +karakters aangeven met het escape-karakter '\' (backslash). +Ook hier betekent '\n' een newline, en met '\0' wordt de +ASCIIwaarde nul aangeduid. (Gewoon een 0 had ook gemogen, +maar zo is het duidelijker dat het een karakter betreft.) + +De vreemd uitziende '||' is een operator die staat voor +logisch-of (logical or). Als 1 van de afzonderlijke +uitdrukkingen niet-nul (ofwel logisch waar) is, is de hele +uitdrukking waar. We springen dus uit de lus als het eerste +karakter van het array 'naam' een spatie OF een newline OF +een nul is. Het bijzondere van de '||' vergeleken met de OR +uit BASIC of PASCAL, is dat er niet meer gerekend wordt dan +strikt noodzakelijk is: na de eerste deeluitdrukking (van +links gezien) die logisch waar is moet de hele uitdrukking +namelijk waar zijn, en hoeven we niet verder te rekenen. + +De tegenhanger van de logische-of is de logische-en (logical +and), die met '&&' wordt aangeduid. Hier echter is de +uitdrukking onwaar als 1 van de deeluitdrukkingen onwaar is. +Ook hiervoor geldt dat er zo min mogelijk wordt gerekend: +zodra een onware deeluitdrukking is gevonden, is de hele +uitdrukking onwaar, en stopt de berekening. Deze '&&' komen +we elders in het programma nog tegen! + +Even een stukje teruggaand zien we: + + gets(naam, STRLEN); + +STRLEN is een helemaal in het begin van het programma +gedefinieerde constante met de waarde 80. Hier is ook het +char array 'naam' gedeclareerd, met dezelfde lengte. De +standaardfunctie 'gets' leest een regel in van het +toetsenbord t/m de return, maar maximaal STRLEN-1 karakters, +omdat de tweede parameter de lengte van het array aangeeft. +Vervolgens wordt er nog een nul achtergeplakt, om het einde +van de string aan te geven. Als functie-return geeft 'gets' +de eerste parameter terug (een char pointer). In dit geval +doen we niets met deze functie-return. + +Na het 'if' statement staat tenslotte: + + printf("\nDe soundex-code is: %s\n\n", soundex(naam, code)); + +Hier zien we een nog onbekende format-specificatie, de '%s'. +Het zal niemand wel zeer verbazen dat dit voor 'string' +staat. De erbij behorende parameter moet naar een string +wijzen, een char pointer dus. De functie 'soundex' berekent +de soundex-code, en heeft als functie-return de waarde van +de tweede parameter, een char pointer. Op deze manier +pointers onveranderd teruggeven is heel gebruikelijk bij +string functies in C, zodat er meteen kan worden +doorgerekend. (Let wel: de pointer mag dan ongewijzigd zijn, +de string waarnaar die pointer wijst is dat natuurlijk +niet!) + +De functie 'soundex' berekent hier de soundex-code van de +string 'naam' en plaatst deze code in de string 'code'. +Natuurlijk moet 'code' dan wel voldoende ruimte bieden voor +de code, 'soundex' kan dit namelijk niet controleren. Terug- +bladerend naar het begin van het programma zien we dat het +array 'code' 5 char groot is, precies voldoende dus voor de +vier karakters en een afsluitende nul. + +Binnen 'soundex' zelf wordt - na de declaraties - eerst de +char pointer (dit korten we in het vervolg maar af tot: char +*) 'old_dst' gelijk gemaakt aan 'dst'. (Een afkorting van +'destination", oftewel 'bestemming'. Maar goed, "what's in a +name?") Dit moeten we doen omdat de pointer 'dst' veranderd +zal worden in de routine, en we willen de oorspronkelijke +waarde als functie-return gebruiken. + +Nadat 'cur_len' - het aantal codesymbolen tot nu toe - nul +is gemaakt, zien we: + + if (*src) { + +Met '*src' halen we het karakter op waar 'src' naar wijst. +Als dit karakter de waarde nul heeft is de string blijkbaar +leeg, en hoeft er niets gecodeerd te worden. Met + + *dst++ = toupper(*src++); + +wordt er 1 karakter van '*src' naar '*dst' gekopieerd, nadat +het tot hoofdletter is gemaakt. Ook worden beide pointer met +1 opgehoogd. Dat is nogal veel voor een enkel statement; zo +compact programmeren is typisch voor C. Laten we eens kijken +wat precies wat doet in dit statement. + +Om een van char - indien van toepassing - een hoofdletter te +maken is de standaarfunctie 'toupper' gebruikt. Deze heeft +een char parameter, en ook een char functie-return. + +Bij de '*dst++' en de '*src++' moet ik eerst wat over de +'++' operator vertellen: het maakt namelijk nogal wat uit of +de '++' voor of na de variabelenaam gebruikt wordt: in het +verleden waren we alleen geinteresseerd wat het effect was +op de variabele, en dat is in beide gevallen hetzelfde. De +waarde van de uitdrukking is echter heel anders: + + x = ++y; + +heeft hetzelfde effect als + + ++y; + x = y; + +en: + + x = y++; + +heeft hetzelfde effect als + + x = y; + ++y; + +Dus als we de '++' voor een variabelenaam gebruiken wordt de +waarde teruggegeven die de variable krijgt na het verhogen, +in het andere geval wordt de oude waarde teruggegeven (maar +de variabele wordt natuurlijk wel verhoogd!) Het statement + + *dst++ = toupper(*src++); + +heeft dus hetzelfde effect als + + *dst = toupper(*src); + ++dst; ++src; + +De eerste manier is natuurlijk bondiger en efficiânter, +hoewel niet echt begrijpelijker. De meeste C-programmeurs +zullen toch de korte methode kiezen. + +Even een technisch puntje: uit het bovenstaande blijkt dat +de operator '++' eerst wordt uitgevoerd, en daarna de '*'. +Je zou dus kunnen denken dat de '++' een hogere prioriteit +heeft dan de '*', maar dit is niet waar, ze hebben beide +dezelfde: alleen worden dit soort unaire operatoren van +rechts-naar-links uitgevoerd. Dit lijkt misschien onlogisch, +maar heeft meestal tot gevolg dat de unaire operator die het +dichtst bij de variabele staat het eerst wordt uitgevoerd. +Alleen het feit dat de '++' in bovenstaand voorbeeld achter +de variabele is gebruikt doet het wat onoverzichtelijk +lijken! + +Na dit statement komen we in een while-lus, die net zolang +doorlopen zal worden tot de lengte van de code-string 4 is, +of er geen karakters meer te coderen zijn. Het volgende +statement dat misschien enige uitleg behoeft is: + + alfa_pos = toupper(*src++) - 'A'; + +Hier zien we weer zo'n haal-en-ophoog constructie als +voorheen. Wat we echter ook zien is dat we met karakters net +zo kunnen rekenen als getallen! De variabele 'alfa_pos' is +van het int-type, en we zien dus ook dat dit soort +omzettingen door C automatisch worden gedaan. De variabele +'alfa_pos' bevat nu de plaats in het alfabet (van 0 t/m 25) +als het karakter een letter was. Zo niet, dan is 'alfa_pos' +kleiner dan 0 of groter dan 25. Door hierop te testen kunnen +we niet-letters negeren. + +De bij de positie in het alfabet behorende code wordt nu +berekend met: + + new_code = "01230120022455012623010202"[alfa_pos]; + +Ai! Dat ziet er vreemd uit, nietwaar? Een string met een +array-index erachter, hoe kan dat? Wel, zo vreemd is dat +niet. Op het moment dat C iets tussen "" tegenkomt zal deze +string ergens in het geheugen worden gezet (de afsluitende +nul wordt automatisch toegevoegd). In de expressie waarin de +string werd gevonden wordt met een char * naar deze string +verder gewerkt. En een pointer met een index erachter kan +natuurlijk zonder problemen worden gebruikt. Het resultaat +lijkt dus wat op de MID$-functie in BASIC, alleen wordt er +maar een enkel karakter uitgelicht, en tellen we vanaf 0. + +De het begrijpen van de rest van de functie mag nu weinig +problemen opleveren, vooral omdat er in commentaarregels +wordt aangegeven wat er gebeurt. + +Nog een laatste opmerking: bij het gebruik van lange +compound statements (tussen { }, remember?) na whileen +ifstatements e.d. is het een goede gewoonte om na het +afsluitende } een kort commentaar te gebuiken om aan te +geven bij welke 'while' of 'if' etc. het hoort. Ook het +telkens inspringen na 'while', 'if', etc. komt de +leesbaarheid zeer ten goede! Dat maakt het weer een stuk +gemakkelijker om fouten in het programma te vinden. Vooral +nietgepaarde { en } maken compilers vaak nogal, eh... +spraakzaam. + +Robert Amesz diff --git a/sunrise_special/3/de_programmeertaal_c_deel_4.md b/sunrise_special/3/de_programmeertaal_c_deel_4.md new file mode 100644 index 0000000..04cb18b --- /dev/null +++ b/sunrise_special/3/de_programmeertaal_c_deel_4.md @@ -0,0 +1,464 @@ +# D E P R O G R A M M E E R T A A L C - D E E L V I E R + + + +## H E T F I L E S Y S T E E M V A N C - I N L E I D I N G + +De meeste programmeertalen stammen nog uit de tijd van de +teletypes en de grote mainframes. Alle informatie die de +computers toen konden tonen en verwerken bestond uit tekst +en getallen. Dit heeft grote invloed gehad op het +filesysteem van de huidige computers: deze zijn in principe +allemaal karakter- en byte-georiânteerd. Files worden gezien +als een rij achter elkaar staande karakters of bytes. Wat al +die bytes betekenen, en wat ermee gedaan moet worden mag de +gebruiker zelf beslissen. Vanuit C kun je files op twee +manieren benaderen: als binaire file en als tekstfile. + + +## F I L E - H A N D L E S E N F I L E - P O I N T E R S + +Wat enigszins verwarrend is, is het feit dat C eigenlijk +twee verschillende niveaus van fileroutines kent. Op het +laagste niveau wordt met "file handles" gewerkt, op het +andere met "file pointers". Beide benaderingen zijn totaal +verschillend, en kunnen niet zonder meer door elkaar worden +gebruikt. + +Het laagste niveau is het niveau van de "file handles". Dit +komt overeen met het laagste niveau zoals dat onder UNIX +gebruikt werd op de PDP11. (Daar is de taal C tenslotte voor +ontwikkeld.) De functies op dit niveau waren - voor zover ik +weet - gewoon routines van het operating system, die binnen +C gebruikt werden. + + +## F I L E H A N D L E S + +Een file handle is in feite niets anders dan een klein +geheel getal. Natuurlijk kan de gebruiker niet zelf dit +getal uitkiezen, dat doet het systeem op het moment dat een +bestand wordt geopend. Met deze file-handle kunnen we vanaf +dat moment bestanden lezen en schrijven, en het file +uiteindelijk sluiten. Op dit niveau kunnen we alleen een +(deel van een) bestand in een (zelfgekozen) buffer inlezen, +of vanuit een buffer naar een bestand schrijven. Ook de +grootte van de buffer is vrij te kiezen. + +Dit klinkt vrij primitief, en dat is het ook. Voor sommige +toepassingen is het echter voldoende, en de snelheid van +deze functies is een stuk hoger dan de meer uitgebreide, +maar daardoor meer gecompliceerde functies met file +pointers. Niet alle C-compilers kunnen met file handles +werken, en op deze manier met files werken komt vrij zelden +voor. Vandaar dat file handles hier nogal summier aan bod +zullen komen. + +Nvdr. Zie ook Sunrise Special #2, de MSX-DOS 2 cursus +behandelt ook file handles, en dit komt bijna overeen met de +file handles in C. + +## W E R K E N M E T F I L E H A N D L E S + +Het openen van een file gaat als volgt: + + open(naam, mode) + +Als parameters hebben we 'naam' (een char *) en 'mode' (een +int). De laatste moet de waarde 0 hebben als we een bestand +willen lezen, 1 om te schrijven, en 2 voor beide. Als het +openen gelukt is geeft de functie een file-handle terug, zo +niet dan ontstaat de waarde ERROR (ofwel -1). + +Lezen en schrijven kan met de functies: + + read(handle, buffer, aantal) + write(handle, buffer, aantal) + +De 'handle' moet de filehandle van een correct geopend +bestand zijn, 'buffer' een char * naar een blok geheugen, en +'aantal' de hoeveelheid bytes die we willen lezen of +schrijven. De functie geeft het daadwerkelijke aantal +gelezen of geschreven bytes terug, of -1 bij fouten. + +Na afloop sluiten we het bestand met: + + close(handle) + +Als alles goed ging krijgen we de waarde 0 terug, anders -1. + + +## F I L E P O I N T E R S + +File pointers zijn inderdaad pointers, maar waar ze precies +naar 'pointen' gaat alleen het filesysteem wat aan. File +pointers worden - net als file handles - bij het openen van +een file aan ons doorgegeven. Wij op onze beurt moeten de +file pointer weer gebruiken in alle functies die we bij dat +bestand willen gebruiken. + +Door files via file pointers te benaderen worden onze +mogelijkheden een stuk groter. Alle I/O functies lopen +intern via file pointers, ook bijvoorbeeld 'printf'. Met +file pointers kunnen we niet alleen lezen en schrijven van +en naar bestanden op schijf, maar kunnen we ook de in- en +uitvoerapparaten bereiken. We hoeven ook niet meer zelf onze +in- en uitvoerbuffers te kiezen, alles wordt verder door het +systeem geregeld. + +Buiten dat zijn er nog een drietal standaard "bestanden" +beschikbaar, die we niet hoeven (sterker nog: mogen) openen +of sluiten. Die aanhalingstekens staan daar omdat het in +feite invoer van het toetsenbord, en uitvoer naar het +beeldscherm betreft. Deze drie bestanden zijn: + +stdin oftewel: standaard invoer. Dit is gebufferde invoer + via het toetsenbord. Gebufferd betekent hier dat we + de gewone regeleditor gebruiken zoals onder DOS, en + dat pas na een return het eerste karakter + beschikbaar is. + +stdout oftewel: standaard uitvoer, het beeldscherm. + +stderr oftewel: standaard foutboodschap uitvoer, eveneens + het beeldscherm. + +Functies zoals 'printf' sturen al hun uitvoer naar 'stdout', +weer andere halen hun gegevens uit 'stdin'. Door de waarden +in 'stdin' of 'stdout' te vervangen door andere file +pointers kunnen we bijvoorbeeld zorgen dat 'printf' zijn +uitvoer op een ander apparaat doet. + + +## B I N A I R E F I L E S E N T E K S T F I L E S + +Bij het openen van een file moeten we niet alleen kiezen of +we willen lezen of schrijven (of beide) maar ook of het als +een binair of een tekstfile moet worden behandeld. Je kunt +je afvragen: waarom dit onderscheid? Tenslotte is het +onderscheid tussen een rij bytes en een rij 8-bit ASCII +karakters alleen een kwestie van interpretatie, en dat is +typisch een zaak voor de programmeur. Toch is er een +onderscheid, en dit hebben we te danken (wijten?) aan UNIX +en CP/M. + +De ASCII code is oorspronkelijk ontworpen voor gebruik met +teletypes, en uit die tijd stammen nog een groot aantal +controlecodes die we nog in de ASCII-tabellen aantreffen, +meestal met geheimzinnig aandoende drie-letterige +afkortingen, zoals SYN, SOH, EOT, enzovoort. Bij teletypes +zijn wagenterugloop (carriage return, kortweg CR) en +regelopvoer (line feed, kortweg LF) twee verschillende +acties, die dus ook allebei een eigen code hadden gekregen. +Voor een nieuwe regel moeten zowel een CR en een LF gebruikt +worden. In UNIX - die blijkbaar in de begintijd niet met +ASCII werkte - was voor die actie een enkele code, een +'newline' nodig (het karakter '\n'). + +Dit geeft problemen. C gaat uit van een enkele newline, waar +in onze ASCII files twee codes, een CR en LF staan. Oeps. +Hoe lost C dit op? Wel, bij het lezen van een CR en een LF +wordt maar een van de codes doorgegeven, gewoonlijk de LF, +en die wordt binnen de C-omgeving als newline gebruikt. +Omgekeerd wordt bij schrijven voor iedere newline een CR en +een LF geschreven. + +Het tweede probleem stamt uit de CP/M tijd, de voorloper van +zowel MSX-DOS als MS-DOS. CP/M werkt met records van 128 +byte elk, en de grootte van een file is alleen in records +bekend, en niet in bytes zoals in MSX-DOS en MS-DOS. De +consequentie daarvan is, is dat er na het laatste karakter +in een tekstfile nog maximaal 127 loze karakters konden +volgen. Lastig. Daarom werd er afgesproken dat als een +tekstfile het laatste 128 byte record niet exact wist te +vullen er een zgn. end-of-file karakter moest worden +geschreven, code 26 oftewel control-Z. Veel programma's +schreven zelfs altijd zo'n code als laatste karakter, of +rekenden erop dat die code altijd aanwezig was. (Een goede +kans: 127 tegen 1. Zulke programma's liepen niet vaak tegen +de lamp.) C houdt zich aan deze conventie, en geeft bij +tekstfiles een EOF zodra een control-Z wordt gelezen, of +schrijft een control-Z bij het sluiten ervan. + +## G E B R U I K V A N F I L E - P O I N T E R S + +In STDIO.H staat de typedefinitie van een file - die heet +FILE (met hoofdletters) - en filepointer variabelen kunnen +we declareren met bijvoorbeeld: + + FILE *een_file; + +Met de '*' geven we aan dat het een pointer-variabele +betreft. De variabele hebben we nodig om na het openen van +een file de filepointer te kunnen opslaan; tenslotte willen +we het bestand later nog kunnen lezen of schrijven, en +uiteindelijk sluiten, en voor al die acties is de +filepointer nodig. Het openen gaat als volgt: + + fopen(name, mode) + +De functie-return is van het type FILE *, en als het openen +mislukt krijgen we een NULL. Zowel "name" als "mode" zijn +van het type char *, en wijzen naar strings. Hierbij is +"name" de naam van het bestand en "mode" de manier waarop we +het bestand willen gebruiken, wat kan zijn: + +"r" tekstfile lezen ("read") +"w" tekstfile schrijven; wist het oude bestand. + ("write") +"a" als "w", maar voegt tekst toe aan het einde van een + bestand, en wist het oude bestand niet. ("append") + +Vaak kan lezen en schrijven worden gecombineerd: + +"r+" tekstfile lezen, maar ook schrijven +"w+" tekstfile schrijven, maar ook lezen +"a+" tekst toevoegen, maar ook lezen + +Voor binaire bestanden moet er nog een "b" worden +toegevoegd, en dan krijgen we "rb", "wb", "ab", "r+b", +enzovoort. + +Helaas kennen niet alle systemen alle manieren van lezen en +schrijven; een minimum is echter wel "r", "w", "rb" en "wb". + + + +## L E Z E N M E T F I L E P O I N T E R S + +Een typische manier om een bestand te openen in c is als +volgt: + + if ((een_file = fopen("help.txt", "r")) == NULL) { + printf("Helptekst niet op deze schijf!\n"); + return; } + +Hier onderbreken we dus de huidige functie op het moment dat +een bestand niet beschikbaar blijkt te zijn, en als het +bestand wel geopend kan worden is de filepointer meteen +opgeslagen in 'een_file'. Dit laat maar weer eens zien hoe +er in C zowel simpel, robuust als compact kan worden +geprogrammeerd. (Probeer hetzelfde maar eens in BASIC of +Pascal. Turbo Pascal wel te verstaan, want in standaard +Pascal is het al helemaal niet te doen.) + +Maar laten we ervan uitgaan dat het bestand geopend kon +worden. In dat geval kunnen we het file gaan lezen, en daar +zijn verschillende functies voor, zoals: + + getc(filepointer) + fgetc(filepointer) + fgets(buffer, aantal, filepointer) + +De functies 'getc' en 'fgetc' doen precies hetzelfde, al +zijn er - officieel tenminste - intern een paar verschillen. +Beide lezen een karakter van een file, en verwachten een +filepointer, voorgesteld door 'filepointer', als parameter. +Het karakter wordt - let goed op! - als int teruggegeven, +omdat de constante EOF (die we krijgen als we een karakter +proberen te lezen na het einde van het bestand) niet in een +char kan worden doorgegeven. + +De functie 'fgets' leest een hele regel tegelijk (dus t/m +'\n') in 'buffer' (een char *) maar nooit meer dan 'aantal' +- 1 karakters. Tevens wordt een afsluitende 0 toegevoegd. De +functie geeft de waarde 'buffer' terug, tenzij er een fout +is opgetreden, of voorbij het einde van het bestand wordt +getracht te lezen: dan krijgen we NULL. Let er wel op dat de +buffer voldoende groot is. Als er een char array gebruikt +wordt met tenminste 'aantal' elementen kan er niets fout +gaan. + +Omdat dit zo vaak voorkomt zijn er bovendien nog de twee +functies + + getchar() + gets(buffer, aantal) + +Deze zijn precies gelijk aan respectievelijk: + + getc(stdin) + fgets(buffer, aantal, stdin) + +Na afloop moeten we een file sluiten met + + fclose(filepointer) + +Ging alles goed dan krijgen we 0 terug, anders EOF. +Overigens zullen bij het beeindigen van een programma alle +nog open files automatisch gesloten worden. + + +## S C H R I J V E N M E T F I L E P O I N T E R S + +Voor het schrijven naar een file kunnen we van de volgende +functies gebruik maken: + + putc(karakter, filepointer) + fputc(karakter, filepointer) + fputs(string, filepointer) + fprintf(filepointer, ...) + +Met 'putc' of 'fputc' schrijven we een 'karakter' (een char) +naar een file. We krijgen EOF terug bij een fout, en anders +0. Darentegen schrijft 'fputs' alle karakters van 'string' +(een char *) tegelijk weg, met uitzondering van de +afsluitende 0. Bij deze functie krijgen we geen waarde +terug. Tenslotte 'fprintf' doet precies hetzelfde als +'printf', alleen schrijft deze functie naar een file. De ... +geven hier aan dat hier een lijst met parameters moet volgen +zoals bij 'printf'. Ook hier wordt geen waarde +teruggegeven.. + +De functies + + putchar(karakter) + puts(string) + +komen overeen met respectievelijk: + + putc(karakter, stdout) + fputs(string, stdout) + + +Ook na schrijven moet een bestand worden gesloten. + +Als laatste een functie die eigenlijk overal buitenvalt, +namelijk: + + unlink(filenaam) + +Hiermee kan een file 'filenaam' gewist worden. Deze functie +is zeer gevaarlijk, omdat (meestal) ook wildcards ('?' of +'*') zijn toegestaan, en een fout in het programma kan hier +wel heel vervelende gevolgen hebben. Bij succes wordt de +waarde 0 teruggegeven, anders -1. + +De naam 'unlink' is wederom een overblijfsel van Unix, die +op een wat andere manier met files omgaat. Met 'unlink' +wordt uit de directory van de huidige gebruiker de +referentie ('link') naar het file gehaald, en het file zelf +wordt pas gewist als alle referenties ernaar verdwenen zijn. + + +## 2 . 3 W A T N I E T A A N B O D K W A M . . . + +In de officiâle C-standaard bestaan nog een hoop andere +functies met files. Een aantal ervan (zoals 'seek' en +'tell') kunnen door de meeste C-compilers voor de Z80 niet +op de juiste wijze worden geãmplementeerd omdat het type +'long' ontbreekt. Andere functies ontbreken vanwege de +verschillen tussen UNIX en CP/M dan wel MSX-DOS. Sommige +ontbreken gewoon omdat men het blijkbaar niet de moeite +waard vond ze te programmeren. Voor microcomputers moet je +vaak een keuze maken, en de filesystemen nemen zonder meer +al het grootste deel van de standaardbibliotheken in beslag. +Wie meer wil weten moet de documentatie van de +desbetreffende compiler eens goed doorlezen. + + +## E E N V O O R B E E L D + + +Het aantal woorden in een file. + +Ook in deze aflevering een voorbeeldprogrammaatje. In +afwijking met voorgaande afleveringen is hier niet de hele +source opgenomen, maar alleen de belangrijkste functie. De +rest van het programma moet de lezer zelf maar eens +bestuderen; veel nieuws is er overigens niet in te vinden. + +Onderstaand programma zou vooral handig zijn geweest in de +hoogtijdagen van de Amerikaanse pulp-magazines. Vooral Isaac +Asimov - vorig jaar overleden - schroomde niet om in +heruitgaves van zijn oude verhalen precies te vertellen +hoeveel hem voor het publiceren van een bepaald verhaal +betaald werd, en hoe het bedrag werd berekend. + +De uitgevers betaalden namelijk per geschreven woord. +Afhankelijk van de kwaliteit van het verhaal en de +bekendheid en populariteit van de auteur lag dit bedrag +tussen de halve en twee dollarcent per woord. We praten hier +weliswaar over de dertiger en veertiger jaren, maar zelfs +dan is wel duidelijk dat de schrijverij voor de meesten niet +meer kon zijn dan een liefhebberij. Voor Asimov zelf duurde +het tot in de jaren vijftig voor hij full-time schrijver +werd, en tegen die tijd had hij al een carriäre als chemicus +achter de rug. + +``` + /* Tel de woorden. Geeft het aantal woorden in */ + /* een file. Als het file niet geopend kon */ + /* worden -1 */ + int telw(file_naam) + char *file_naam; + { + FILE *infile; /* File om uit te lezen */ + int teller; /* Lopend totaal */ + int karakter; /* Moet int zijn vanwege EOF */ + char inwoord; /* TRUE --> midden in een woord */ + + + if ((infile = fopen(file_naam, "r")) == NULL) + return -1; /* File kan niet geopend worden */ + + teller = 0; /* Geen woorden geteld */ + inwoord = FALSE; /* Start niet in woord */ + + /* Al 't werk gebeurt in dit while-statement */ + while ((karakter = getc(infile)) != EOF) + if (inwoord) + inwoord = ! leeg((char)karakter); + else + if (! leeg((char)karakter)) { + inwoord = TRUE; + teller++; } + + fclose(infile); + + return teller; + } +``` + +Allereerst wordt geprobeerd het file te openen, en als dat +mislukt wordt de waarde -1 teruggegeven. Daarna kan het +echte werk beginnen. + +De gebruikte methode is heel eenvoudig. De variabele +'inwoord' geeft aan of we midden in een woord zitten, of +erbuiten. Zodra we van buiten een woord in een woord komen +verhogen we 'teller' met 1. Na afloop bevat teller dan +precies het aantal woorden. + +Elders in het programma is de functie 'leeg' gedefinieerd, +die aangeeft of een karakter 'lege ruimte' voorstelt, zoals +een spatie, een newline, enzovoort. Een klein probleem hier +is dat de variabele 'karakter' van het type int is, en +'leeg' een char als parameter wil. Met '(char)' kunnen we +zo'n conversie afdwingen; dit wordt een 'cast' genoemd. Meer +hierover in de volgende aflevering. + +Het losse uitroepteken is de logisch-niet operator. Deze +geeft 0 (FALSE) als de uitdrukking erachter niet-0 (TRUE) +is, en omgekeerd. + +In de uitdrukking achter 'while' wordt 'getc' net zolang +aangeroepen tot een EOF gelezen wordt. Dit is een +gebruikelijke manier om een heel file te lezen. De variabele +'karakter' moet perse van het type 'int' zijn, omdat anders +de int-waarde automatisch naar een char wordt geconverteerd, +waarna er niet meer op EOF kan worden getest. + +Wie zich overigens afvraagt waarom er na de 'gets' (in +'main') zo ingewikkeld wordt gedaan, dit is omdat de newline +die na de aanroep van 'gets' in de string zit niet wordt +geaccepteerd als laatste karakter van een filenaam, en dan +zou het file niet geopend kunnen worden. Vandaar. + +Zo, dat was het dan weer voor deze keer. Zo langzamerhand +zal de lezer genoeg van C kennen om er al serieuze +programmaatjes in te kunnen schrijven. Dus hou vol, zelfs +als je denkt: "C is a harsh mistress!" + +Robert Amesz + \ No newline at end of file diff --git a/sunrise_special/3/file_handles.md b/sunrise_special/3/file_handles.md new file mode 100644 index 0000000..3cd4df3 --- /dev/null +++ b/sunrise_special/3/file_handles.md @@ -0,0 +1,185 @@ + +# F I L E H A N D L E S + + +In deel ÇÇn van de DOS2-cursus heb je kunnen zien wat File +Handles zijn. In deze tekst wordt duidelijk gemaakt hoe je +ze dient te gebruiken. Dit gaat aan de hand van een +voorbeeld-source om een file mee te kopiâren. + +Bij kopiâren komen de belangrijkste aspecten aan bod: +openen, aanmaken, lezen, schrijven en sluiten. + + +## M A C R O O T J E + +``` +AdrBDOS: EQU 5 ;Adres BDOS onder DOS + ;Is #F37D onder BASIC + +BDOS: MACRO @Func ;Macrootje + LD C,@Func + CALL AdrBDOS + ENDM +``` + +Deze macro maakt het voor mij iets makkelijker. Het scheelt +typewerk en het is duidelijk. Als je niet weet hoe macro's +werken, moet je de tekst daarover lezen op de vorige +Special. + + +## E Q U A T E S +``` +Open: EQU #43 ;File Handle openen +Create: EQU #44 ;File aanmaken en openen +Close: EQU #45 ;File Handle sluiten +Read: EQU #48 ;File Handle lezen +Write: EQU #49 ;File Handle schrijven +TermError: EQU #62 ;Terminate with errorcode +``` +Dit zijn de BDOS-functies die ik gebruik in deze source. + + + +## O P E N E N +``` + LD DE,Filename + LD A,%0001 ;No write + BDOS Open + JR NZ,Error + PUSH BC ;File Handle in B +``` +Met dit stukje source open je een File Handle. Functie 43H +werkt als volgt: + + Input: C = 43H (_OPEN) + DE = Drive/path/file in ASCIIZ + A = Open mode. b0 geset => niet schrijven + b1 geset => niet lezen + Output: A = Errorcode + B = Nieuwe File Handle + +Een ASCIIZ-string is een string die afgesloten wordt met +ASCII code 0 (Zero). Als er geen fout optreedt, is A 0. De +BDOS van DOS2 geeft zelf voor het terugkeren een OR A, dus +je hoeft dat zelf niet meer te doen. Je kunt meteen testen +op het Z bit, en evt. springen naar de error routine (zie +onderaan). + +B wordt hier gePUSHt, omdat B wordt gebruikt in de volgende +BDOS routine. B wordt weer gePOPt om de File Handle te +sluiten. Als je een File Handle de hele tijd (niet erg +exact, maar het is duidelijk) nodig hebt, kun je hem het +beste ergens in de buurt van de ASCIIZ string zetten. Mijn +favoriete stekje is de Zero byte, die je immers toch niet +meer gebruikt. + + +## L E Z E N +``` + LD DE,Buffer + LD HL,Length + BDOS Read + JR NZ,Error +``` + Input: C = 48H (_READ) + B = File Handle + DE = Buffer adres + HL = Aantal te lezen bytes + Output: A = Errorcode + HL = Aantal gelezen bytes + +De File Handle was nog goed. Length staat bij de string, +da's overzichtelijker. Buffer is gewoon de byte die volgt na +de laatste byte van het programma. Als je een grote file +inleest, moet je erop letten dat je niet over het hoogste +adres heengaat. Daar wordt later misschien nog op ingegaan +bij de bespreking van de Mapper Support Routines van DOS2. + +Een file van onbekende grootte moet je gewoon inlezen door +in HL een zo groot mogelijk (rekening houdend met hoogste +adres) getal in te vullen. Als de HL die terugkomt even +groot is als de input-HL, moet het lezen gewoon herhaald +worden. + + +## O V E R E N S L U I T E N +``` + POP BC ;File Handle terughalen + BDOS Close + JR NZ,Error +``` + Input: C = 45H (_CLOSE) + B = File Handle + Output: A = Errorcode + +Dit is niet noodzakelijk, maar wel netter. (Had ik maar zo'n +functie om de troep op mijn kamer op te ruimen...) + + +## C R E A T E +``` + LD DE,Filename + LD A,DestDrive + LD (DE),A + LD A,%0010 ;No read + LD B,0 ;File attributen + BDOS Create + JR NZ,Error + PUSH BC +``` +Eerst even het adres van de string inlezen, die vervolgens +aanpassen en de registers goed zetten. + + + Input: C = 44H (_CREATE) + DE = Drive/path/file in ASCIIZ + A = Open mode. b0 geset => niet schrijven + b1 geset => niet lezen + B = Gewenste attributen + Output: A = Errorcode + B = File Handle + + +## S C H R I J V E N +``` + LD DE,Buffer + LD HL,Length + BDOS Write +``` + Input: C = 49H (_WRITE) + B = File Handle + DE = Buffer adres + HL = Aantal te lezen bytes + Output: A = Errorcode + HL = Aantal gelezen bytes + + +## F O U T M E L D I N G E N +``` +Error: LD C,TermError + LD B,A ;Als A=0 dan geen error + JP AdrBDOS +``` +DOS2 heeft een hele mooie functie: Terminate with errorcode: + + Input: C = 62H (_TERM) + B = Errorcode + +Als B=0, komt er geen error op het scherm. Alle +foutmeldingen zijn (uiteraard) in DOS2-stijl. + +``` +DestDrive: EQU "H" +Filename: DB "A:\FILHANDL.GEN",0 +Length: EQU 1057 + +Buffer: END +``` +DestDrive is de bestemmingsdrive. De lengte moet kloppen met +de originele file. Als de lengte te groot is, krijg je "*** +End of file". + +Kasper Souren + \ No newline at end of file diff --git a/sunrise_special/3/getallen_printen.md b/sunrise_special/3/getallen_printen.md new file mode 100644 index 0000000..49843bd --- /dev/null +++ b/sunrise_special/3/getallen_printen.md @@ -0,0 +1,213 @@ + + G E T A L L E N P R I N T E N + + + Het komt bij programmeren vaak voor dat je getallen op het + scherm wilt zetten. In BASIC gaat dat meestal decimaal, dat + is in BASIC ook het makkelijkst. In ML is decimaal minder + makkelijk, binair of hexadecimaal is daar logischer. Ik zal + nu een drietal routines behandelen om in ML getallen + respectievelijk decimaal, hexadecimaal en binair op het + scherm te zetten. + + + D E C I M A A L + + Getallen in decimaal op het scherm zetten, in BASIC heel + makkelijk maar in ML toch iets moeilijker. Met onderstaande + routine kun je 16 bits getallen in ML decimaal printen met + voorloopnullen en naar keuze 1, 2, 3, 4 of 5 cijfers. + + De voorloopnullen zijn overigens niet gedaan voor de netheid + maar om de routine simpel te houden. In BASIC moet je moeite + doen om de voorloopnullen erbij te zetten, bij ML moet je + juist moeite doen om ze weg te laten. + + Tot zover de inleiding, laten we nu maar snel verdergaan met + de source. Zoals gewoonlijk staat de source op de disk als + ASCII file. + + + ; D E C I M A A L . A S C + ; Roep naar keuze DIGIT1, 2, 3, 4 of 5 aan voor uitvoer + ; met het gewenste aantal cijfers + ; In : HL=getal + ; Uit:Getal wordt met &HA2 op scherm gezet + ; Registers AF, DE, BC en HL worden gebruikt + ; Door Stefan Boer + ; (c) Ectry 1993 + ; Sunrise Special #3 + ; (c) Sunrise 1993 + + DIGIT5: LD DE,10000 + CALL PR_DIG + DIGIT4: LD DE,1000 + CALL PR_DIG + DIGIT3: LD DE,100 + CALL PR_DIG + DIGIT2: LD DE,10 + CALL PR_DIG + DIGIT1: LD DE,1 + CALL PR_DIG + RET + + + Door DIGIT5 aan te roepen wordt het getal met 5 cijfers + (digits) geprint, DIGIT4 met 4 cijfers, etc. De routine + PR_DIG (PRint DIGit) kijkt hoeveel maal DE in HL past, en + voert dat getal uit. + + + PR_DIG: XOR A ; teller = 0 + NEXT: LD B,H + LD C,L ; LD BC,HL + OR A ; wis carry, A blijft gelijk + SBC HL,DE ; trek DE van HL af + JR C,OUTPUT ; DE > HL, dan einde lus + INC A ; verhoog teller + JR NEXT + + + Eerst wordt het A register 0 gemaakt, dit is de teller die + bijhoudt hoe vaak DE in HL past. In de lus wordt eerst de + huidige waarde van HL bewaard in BC. PUSHen is hier niet + handig en het is sneller dan LD (...),HL. + + Vervolgens wordt DE van HL afgetrokken. SUB HL,DE bestaat + niet, dus moeten we SBC gebruiken en eerst de carry wissen + met OR A (anders zou een eventuele carry roet in het eten + kunnen gooien bij SBC, SuBtract with Carry). + + Treedt er nu een carry op, dan was DE blijkbaar groter dan + HL (past er dus 0 keer meer in) en verlaten we de lus. + Anders verhogen we de teller en doorlopen we de lus opnieuw. + + + OUTPUT: LD H,B + LD L,C ; LD HL,BC + ADD "0" + CALL &HA2 ; voer waarde uit + RET + + Hier wordt de waarde van HL voordat er de laatste keer werd + afgetrokken weer hersteld, dit is nodig om ook de andere + cijfers te kunnen afdrukken. Vervolgens wordt de ASCII code + van "0" bij A geteld (A bevat het aantal keren dat DE in HL + past), en wordt dit cijfer op het scherm gezet met BIOS + routine CHPUT (&HA2). + + Niet zo'n moeilijke routine, maar wel een handige die je + vaak nodig hebt. En er zijn toch veel beginnende + programmeurs die er moeite mee hebben. Hexadecimale uitvoer + is veel simpeler te programmeren, maar dat is voor de + gebruiker niet zo handig. Ik heb in ieder geval nog nooit + een spel gezien met de score in hexadecimaal! + + + H E X A D E C I M A A L + + De routine om hexadecimaal te printen is niet korter, maar + wel veel simpeler. Hexadecimaal wordt bijvoorbeeld vaak + gebruikt om adressen weer te geven. Genoeg gepraat, hier + komt de routine. De routine zet een getal in DE op het + scherm in 4 digits, met voorloopnullen. De routine is vrij + simpel, dus meer uitleg dan wat achter ; staat is overbodig. + + + ; H E X A M A A L . A S C + ; Print 16 bits getal hexadecimaal + ; In : DE = 16 bits getal + ; Uitvoer naar scherm + ; Gebruikt: AF, HL, BC + ; Door Stefan Boer + ; (c) Ectry 1993 + ; Sunrise Special #3 + ; (c) Sunrise 1993 + + PR_HEX: LD B,0 + LD A,D ; high byte + AND &HF0 ; linker digit + RRCA + RRCA + RRCA + RRCA ; verplaats naar lage nibble + CALL UITHEX ; uitvoer + LD A,D ; high byte + AND &H0F ; rechter digit + CALL UITHEX + LD A,E ; low byte + AND &HF0 ; linker digit + RRCA + RRCA + RRCA + RRCA + CALL UITHEX + LD A,E ; low byte + AND &H0F ; rechter digit + JP UITHEX ; CALL & RET + + UITHEX: LD HL,HEXTAB ; beginadres tabel + LD C,A ; LD BC,A (B was al 0) + ADD HL,BC ; bereken adres in tabel + LD A,(HL) ; haal ASCII code van digit + JP &HA2 ; CALL & RET + + HEXTAB: DM "0123456789ABCDEF" + + + B I N A I R + + Om het verhaal volledig te maken moet ook binair er nog bij, + al zul je dat normaal gesproken toch weinig gebruiken. De + routine is heel kort maar toch iets moeilijker te begrijpen + dan de routine voor hexadecimaal. + + De routine print het getal in C met 8 digits en voorloop- + nullen. Als je een 16 bits getal wilt printen, kun je de + routine natuurlijk gewoon twee keer aanroepen. Bijvoorbeeld: + + LD C,H + CALL PR_BIN + LD C,L + CALL PR_BIN + + Om HL 16 bits af te drukken. De source: + + + ; B I N A I R . A S C + ; Print 8 bits getal binair op het scherm + ; In: C = 8 bits getal + ; Uitvoer naar scherm + ; Gebruikt: + ; Door Stefan Boer + ; (c) Ectry 1993 + ; Sunrise Special #3 + ; (c) Sunrise 1993 + + PR_BIN: LD B,8 ; 8 bits te gaan + BINLUS: LD A,24 ; "0"/2 + RLC C ; roteer C, bit 7 naar carry + RLA ; roteer A, carry naar bit 0 + CALL &HA2 ; uitvoer + DJNZ BINLUS ; dit 8 keer + RET + + + Hier is denk ik nog wel wat uitleg nodig. In het A register + wordt eerst de waarde 24 gezet, dat is de ASCII code van "0" + (48), maar dan ÇÇn bit naar rechts geroteerd. Vervolgens + roteren we register C ÇÇn bit naar links, waarbij bit 7 (het + bit dat we willen afdrukken!) in de carry terecht komt. + Vervolgens roteren we register A ÇÇn bit naar links met RLA, + wat overigens hetzelfde is als RL A alleen sneller en een + byte minder. Hierdoor worden de bits die al in A stonden dus + meegeschoven, en staat de ASCII van "0" in A. Maar bij RL + wordt de carry in bit 0 geschoven. Was de carry 0, dan + gebeurt er niets en staat er "0" in A, was de carry 1, dan + wordt bit 0 gelijk en staat er "1"! Zo gaan we alle bits + langs. + + Kortom, het ziet er ingewikkeld uit maar is eigenlijk heel + simpel! + + Stefan Boer \ No newline at end of file diff --git a/Sunrise Special/3/Getdisk.md b/sunrise_special/3/getdisk.md similarity index 100% rename from Sunrise Special/3/Getdisk.md rename to sunrise_special/3/getdisk.md diff --git a/sunrise_special/3/hybride_call_commandos.md b/sunrise_special/3/hybride_call_commandos.md new file mode 100644 index 0000000..cbc29ec --- /dev/null +++ b/sunrise_special/3/hybride_call_commandos.md @@ -0,0 +1,567 @@ + - HYBRIDE - + + C A L L - 1 - + + + In de serie Hybride artikelen hebben we het deze keer over + CALL commando's. Het CALL commando is aan MSX BASIC + toegevoegd om het mogelijk te maken uw eigen commando's of + toekomstige uitbreidingen te gebruiken. + + De syntax luidt: + + CALL [ (parameter,parameter ...) ] + + In plaats van CALL mag ook het onderstrepingsteken _ worden + gebruikt. + + Kennis van machinetaal is vereist voor het zelf maken van + een CALL commando. BASIC programmeurs kunnen de nieuwe + commando's natuurlijk wel zonder problemen gebruiken in hun + eigen programma's. + + Voordat we ingaan op het maken van een CALL commando wordt + er eerst enige achtergrondinformatie gegeven. + + + U I T B R E I D I N G S P A G I N A + + Een pagina is een stuk geheugen (ROM of RAM) van 16 kB. De + pagina's zijn genummerd van 0 t/m 3. + + Page: Adresbereik: + 0 &H0000-&H3FFF + 1 &H4000-&H7FFF + 2 &H8000-&HBFFF + 3 &HC000-&HFFFF + + De MSX computer heeft standaard pagina's met RAM, MAIN ROM + en Disk ROM. Daar kunnen echter door de fabrikant (in ROM + vorm) of door de gebruiker (in het RAM) uitbreidingspagina's + aan worden toegevoegd. + + Een uitbreidingspagina kan een machinetaalprogramma, een + apparaatuitbreiding, een BASIC-uitbreiding of een BASIC- + programma bevatten. De informatie daarover is opgeslagen in + SLTATR. SLTATR is een gedeelte van het systeemgebied, dat + begint op adres &HFCC9. Er is ÇÇn byte gereserveerd per + mogelijke pagina. Er zijn 4 primaire sloten mogelijk die elk + 4 secundaire sloten kunnen hebben. Elk slot bestaat weer uit + 4 pages, zodat SLTATR 4*4*4=64 bytes lang is. De bits van + de bytes in SLTATR hebben de volgende betekenis: + + Bit 7 BASIC programma (1=ja) + Bit 6 Apparaat uitbreiding (1=ja) + Bit 5 Statement uitbreiding (1=ja) (CALL commando) + Bit 4-0 Ongebruikt + + U kunt het adres dat bij een bepaalde pagina hoort berekenen + met de volgende formule: + + ADRES = &HFCC9 + 16 * primaire gleufnummer + 4 * secundaire + gleufnummer + paginanummer + + Voorbeeld: in uw computer zit het RAM in slot 3-2 en u heeft + een statement uitbreiding in page 1 gemaakt. Het adres wordt + dan: + + &HFCC9 + 16 * 3 + 4 * 2 + 1 = &HFD02 + + Bit 5 staat voor een statement uitbreiding, dus de waarde 32 + (2^5) moet naar adres &HFD02 worden geschreven: POKE &HFD02, + 32. De computer zal nu naar page 1 in slot 3-2 springen als + er een CALL commando wordt gegeven. + + + H E A D E R + + De eerste 16 bytes van een uitbreidingspagina worden samen + ook wel de header genoemd en zijn als volgt opgebouwd: + + Offset: Naam: Bevat: + ------------------------------------------------------------ + +0 ID "AB" + +2 INIT beginadr initialisatie + +4 STATEMENT beginadr statement uitbreiding + +6 DEVICE beginadr apparaat uitbreiding + +8 TEXT beginadr BASIC programma + +10 - 6 bytes gereserveerd + ------------------------------------------------------------ + + Aan het begin van een pagina moeten de letters "AB" (ASCII + &H41 en &H42) staan. De computer herkent daaraan de + uitbreidingspagina. Bij een RESET zal de computer zelf + kijken wat er in de pagina's staat en SLTATR overeenkomstig + invullen. Als u een CALL commando wilt gebruiken zonder een + RESET, dan zult u zelf in SLTATR moeten POKEn, zoals we bij + de uitleg van SLTATR al hebben gezien. + + + S T A T E M E N T U I T B R E I D I N G + + Wij interesseren ons nu alleen voor de statement + uitbreiding. Als er geen statement uitbreiding in de pagina + aanwezig is, moet STATEMENT gelijk zijn aan &H0000. Alleen + page 1 kan een statement uitbreiding bevatten. Er kunnen + problemen ontstaan als bij andere pagina's het veld + STATEMENT is ingevuld. + + Het is overigens logisch dat de statement uitbreiding in + page 1 moet staan. In page 0 staat de BIOS en in page 3 het + systeemgebied, dus die moeten ingeschakeld blijven. Het + BASIC programma staat in page 2 (als het een groot programma + is tot in page 3), dus page 1 is de enige mogelijkheid die + overblijft. + + Als de computer bij het uitvoeren van een BASIC programma + een CALL commando tegenkomt, wordt de naam van het commando + (het woord dat achter CALL staat) in PROCNM gezet. PROCNM + ligt in het systeem gebied, vanaf &HFD89. Alle kleine + letters worden omgezet in hoofdletters en de komma's worden + eruit gehaald (probeert u maar eens: _F,O,R,M,A,T het + werkt!). De naam mag 15 tekens lang zijn. Achter de naam + wordt een ASCII-teken 0 gezet. Daarna gaat de computer alle + pagina's langs die volgens SLTATR een statement uitbreiding + bevatten. + + Als de computer bij STATEMENT een waarde vindt die ongelijk + is aan &H0000, dan springt hij naar dat adres en laat de + besturing verder aan die routine over. De taak van de + routine is nu om te controleren of het het juiste statement + is. + + HL wijst naar het eerste teken na de naam van het CALL + statement in het tokenized BASIC. Spaties worden daarbij + niet meegeteld. Bij bijvoorbeeld CALL FORMAT wijst HL dus + naar de positie NA de T van FORMAT. + + Als de routine ziet dat het de juiste naam is, moet het + statement worden uitgevoerd en moet de routine worden + verlaten met de carry gereset (gelijk aan 0 dus). HL moet + naar het eerste teken na het commando wijzen (het einde van + de regel of een dubbele punt). Bij een CALL statement zonder + parameters is dat dus de oude situatie (bijvoorbeeld + _FORMAT), bij _COLOR(15,0) moet HL wijzen naar de positie + achter het tweede haakje. + + Is het een ander commando, dan moet de routine verlaten + worden met de carry geset (hoog) en HL onveranderd. De + andere registers mogen wel zijn veranderd. + + Samenvatting: + + - CALL statement wordt niet gevonden: verlaat routine met HL + onveranderd en carry hoog + - CALL statement is gevonden: voer CALL statement uit en + verlaat de routine met HL op de positie achter het gehele + CALL statement en de carry laag + + + S T A N D A A R D R O U T I N E + + Om het allemaal wat makkelijker te maken heb ik een + standaardroutine geschreven, die als CALL.ASC op de diskette + staat. U kunt deze routine gebruiken voor al uw CALL + statements. De routine kan ÇÇn, maar ook twee of meer + routines aansturen. Als al het RAM in ÇÇn slot zit (is + meestal zo), dan kunt u maar ÇÇn blok CALL commando's + tegelijk gebruiken. Er is dan namelijk maar ÇÇn page 1 + beschikbaar, en de statement uitbreiding moet altijd in page + 1 staan. + + Achter de standaardroutine staan drie voorbeelden van CALL + commando's, die u bij het maken van uw eigen blok CALL + commando's natuurlijk kunt weglaten. Ik ga deze routine + zometeen uitgebreid bespreken. Maar eerst even dit. + + + N A A R D I S K A S S E M B L E R E N + + Het is het makkelijkst als het blok CALL commando's met een + BLOAD,R kan worden geãnitialiseerd. De CALL code moet echter + op &H4000 staan, en daar kunnen we niet laden onder BASIC. + We moeten daarom twee ORGs gebruiken, ÇÇn voor het + intialisatieprogramma en ÇÇn voor de CALL code. Om het + allemaal toch netjes in ÇÇn .BIN file te krijgen moeten we + naar disk assembleren. + + Ik ga hier uit van WB-ASS2. GEN80 gebruikers zullen de + source dus enigszins moeten aanpassen. Je kunt met GEN80 + trouwens alleen maar naar disk assembleren. Bij WB-ASS2 kan + dit door de vragen die het ASM statement stelt als volgt te + beantwoorden: + + Listing afdrukken? Nee (Ja mag natuurlijk ook) + Ascii listing naar disk? Nee + Mcode in geheugen zetten? Nee + Mcode naar disk? Ja + Relocatie-tabel maken? Nee + + Vervolgens moet nog de filenaam worden ingetypt, + bijvoorbeeld CALL.BIN. WB-ASS2 gaat aan de slag en als + resultaat staat de file CALL.BIN op de diskette, die met + BLOAD"CALL.BIN",R kan worden gestart. + + (Nvdr. De tekst was langer dan 16 kB, u kunt het tweede + gedeelte in het submenu vinden.) + + + + - HYBRIDE - + + C A L L - 2 - + + + + Het is nu hoog tijd voor: + + D E S O U R C E + + ; CALL.ASC + ; Standaardroutine voor het maken van CALL commando's + ; Door Stefan Boer + ; (c) Ectry 1993 + ; Sunrise Special #3 + ; (c) Stichting Sunrise 1993 + + ; (Alleen) naar disk assembleren! + ; Resultaat starten met BLOAD"...",R + + ; Header voor .BIN file + + DEFB &HFE + DEFW EXEC + DEFW ENCALL-&H4001+STCALL + DEFW EXEC + + + Omdat we rechtstreeks een file aanmaken, moeten we zelf + zorgen voor de juiste header. Een BLOAD,R file moet beginnen + met een header van 7 bytes. De eerste byte is altijd &HFE, + hieraan kan een .BIN file worden herkend. Vervolgens 3*2 + bytes beginadres, eindadres en startadres. ENCALL is het + eindadres+1 van de CALL code die vanaf &H4000 staat. De + lengte van dat blok CALL code is dus ENCALL-&H4001. Om het + eindadres te berekenen wordt daar nog het eindadres van de + initialisatie routine bij opgeteld. + + ; Dit startadres moet eventueel omlaag als CALL code lang is + + ORG &HC000 + + ; Initialisatieroutine + ; Kopieer CALL code naar &H4000 + ; En zet bitje in SLTATR + + EXEC: LD A,(&HF342) ; slot RAM page 1 + LD H,&H40 ; PAGE 1 + CALL &H24 ; BIOS routine ENASLT + LD HL,STCALL + LD DE,&H4000 + LD BC,ENCALL-&H4000 + LDIR ; verplaats CALL code + LD A,(&HFCC0) ; slot MAIN ROM + LD H,&H40 + CALL &H24 + + + Hier wordt er RAM geselecteerd op adres &H4000, de CALL code + wordt gekopieerd en vervolgens wordt de MAIN ROM weer terug + gezet op adres &H4000. + + + LD HL,&HFCCA ; &HFCC9 + pagenummer (=1) + LD BC,&H10 + LD A,(&HF342) ; slot RAM page 1 + AND &B00000011 ; primair slotnummer + CLUS1: JR Z,CNEXT + ADD HL,BC ; tel primair*16 erbij op + DEC A + JR CLUS1 + CNEXT: LD BC,4 + LD A,(&HF342) ; slot RAM page 1 + AND A ; zet vlaggen goed + JP P,CEINDE ; is er wel secundair slot + AND &B00001100 ; secundaire gleuf * 4 + RRCA ; secundaire gleuf * 2 + RRCA ; secundaire gleuf + CLUS2: JR Z,CEINDE + ADD HL,BC ; tel secundair*4 erbij op + DEC A + JR CLUS2 + CEINDE: LD (HL),&H20 ; zet bit 5 aan + RET ; einde initialisatie + + + Hier wordt het juiste adres in SLTATR uitgerekend, en op dat + adres wordt de waarde &H20 gezet. Hieraan kan de interpreter + zien dat er een statement uitbreiding in die page zit. + + + STCALL: ; beginadres van code IN FILE + + + Als de BLOAD,R file is ingeladen, staat de CALL code niet op + adres &H4000 maar direct achter de RET van CEINDE. We hebben + dat adres nodig om de CALL code te kunnen verplaatsen en om + het eindadres uit te kunnen rekenen. Vandaar dit "loze" + label. + + + ; CALL code + + ORG &H4000 ; hier begint CALL code + + ; CALL header + + DEFM "AB" + DEFW 0 ; geen initialisatie + DEFW CAL ; startadres CALL code + DEFW 0 ; geen device + DEFW 0 ; geen BASIC + DEFW 0 + DEFW 0 + DEFW 0 + + + ; Hier springt interpreter naar toe bij CALL commando + + CAL: PUSH HL ; HL wijst naar teken na naam + van CALL statement + + ; Kijk of naam van CALL statement overeenkomt met + ; een van de namen in de tabel + + LD DE,TABEL ; begin van de tabel + C_1: LD HL,&HFD89 ; PROCNM bevat naam + LD A,(DE) ; lengte van naam + AND A ; zet vlaggen goed + JR Z,C_ERR ; einde tabel als A=0 + LD B,A ; lengte + INC DE + + C_2: LD A,(DE) ; vergelijk naam in tabel + CP (HL) ; met naam in PROCNM + JR NZ,NEXT1 ; naar NEXT1 als onjuist + INC DE ; volgende letter + INC HL + DJNZ C_2 + + LD A,(HL) ; laatste teken moet nu + AND A ; gelijk zijn aan 0, anders + JR NZ,NEXT2 ; is CALL naam te lang + + + Dit laatste stukje code is nodig om ervoor te zorgen dat het + verschil wordt gezien tussen bijvoorbeeld CALL SUN en CALL + SUNRISE. + + + ; alles Ok, spring naar CALL routine + + EX DE,HL ; HL is plaats in tabel + LD E,(HL) ; low byte sprongadres + INC HL + LD D,(HL) ; high byte sprongadres + EX DE,HL + JP (HL) ; spring naar dat adres + + ; Verkeerde naam, ga naar volgende naam in tabel + + NEXT1: LD C,B + LD B,0 ; BC=B + INC BC + INC BC + EX DE,HL + ADD HL,BC ; sla rest naam + sprongadres + EX DE,HL ; over + JR C_1 ; probeer het nog eens + + ; Naam te lang, ga naar volgende naam in tabel + + NEXT2: INC DE ; sla het sprongadres + INC DE ; over + JR C_1 ; probeer het nog eens + + ; Niet gevonden, einde routine met carry hoog + ; Als in andere sloten ook geen kloppend CALL commando + ; wordt gevonden, zal BASIC foutmelding geven + + C_ERR: POP HL + SCF ; Set Carry Flag + RET + + + Tot zover de "CALL handler". Het is in de code voor CALL + commando's makkelijk om een aantal routines uit de BASIC + interpreter "bij de hand te hebben": + + ; Handige routines + + ILLEGA: LD IX,&H475A ; Illegal function call + JP &H0159 + + SYNTAX: LD IX,&H4055 ; Syntax error + JP &H0159 + + R_BYTE: LD IX,&H521C ; Lees een byte van getokenized + JP &H0159 ; BASIC, resultaat in A + + R_WORD: LD IX,&H6F0B ; Lees een word van getokenized + JP &H0159 ; BASIC, resultaat in DE + + + Hier ontbreekt nog FRMEVL op adres &H4C64, waarmee elke + willekeurige expressie kan worden "geâvalueerd". De + interpreter zal VALTYP (&HF663) en DAC (&HF7F6) vullen met + het resultaat. De namen van de routines die door R_BYTE en + R_WORD worden aangeroepen zijn overigens respectievelijk + GETBYT en FRMQNT. + + + ; Tabel met CALL commando's + + TABEL: DB 4 ; lengte CALL commando + DM "INFO" ; de naam + DW INFO ; het adres + + DB 4 + DM "DSKI" + DW DSKI + + DB 6 + DM "KILBUF" + DW KILBUF + + DEFB 0 ; afsluiten + + + In deze tabel moeten alle namen, lengtes en startadressen + van de CALL statements in het blok CALL code worden gezet. + + Voor de duidelijkheid heb ik nog een drietal voorbeelden + toegevoegd. Op de disk staat de file CALLTEST.BIN, waarmee u + het zelf kunt uitproberen. + + + ; Voorbeelden + + ; CALL INFO + ; Zet melding op het scherm + + INFO: LD HL,TEXT ; begin tekst + INFO_1: LD A,(HL) ; ASCII teken + AND A + JR Z,INFO_2 ; klaar als 0 + CALL &HA2 ; teken naar scherm + INC HL + JR INFO_1 ; volgende teken + + INFO_2: POP HL ; pointer achter statement + XOR A ; wis carry: CALL commando Ok + RET + + TEXT: DM "Standaard CALL routine",13,10 + DM "(c) Ectry 1993",13,10,0 + + ; CALL DSKI (drive,sector,aantal,adres) + ; Lees sectoren in + + DSKI: POP HL ; pointer achter naam + + LD A,(HL) + CP "(" ; check haakje + JP NZ,SYNTAX + INC HL + + CALL R_BYTE ; haal drivenummer + LD (DRIVE),A + + LD A,(HL) + CP "," ; check komma + JP NZ,SYNTAX + INC HL + + CALL R_WORD ; haal start sector + LD (SECTOR),DE + + LD A,(HL) + CP "," ; check komma + JP NZ,SYNTAX + INC HL + + CALL R_BYTE ; haal aantal sectoren + LD (COUNT),A + AND A ; zet vlaggen goed + JP Z,ILLEGA ; Illegal function call als + ; 0 sectoren + + LD A,(HL) + CP "," + JP NZ,SYNTAX + INC HL + + CALL R_WORD ; haal adres (komt in DE) + + LD A,(HL) + CP ")" + JP NZ,SYNTAX + INC HL + + PUSH HL ; bewaar pointer + + LD C,&H1A ; BDOS call SETDMA + CALL &HF37D ; Zet DMA adres op DE + + LD DE,(SECTOR) ; DE=startsector + LD HL,(DRIVE) ; H=#sectoren, L=drive + LD C,&H2F ; BDOS call Absolute Disk Read + CALL &HF37D ; Lees sectoren + + POP HL ; pointer achter statement + XOR A ; wis carry: CALL commando Ok + RET + + ; data voor DSKI routine + + DRIVE: DB 0 + COUNT: DB 0 + SECTOR: DW 0 + + ; CALL KILBUF + ; Wis toetsenbordbuffer + + KILBUF: CALL &H0156 ; BIOS routine + POP HL ; pointer achter statement + XOR A ; wis carry: CALL commando Ok + RET + + ENCALL: END + + + Z E L F A A N D E S L A G + + Het zelf maken van een CALL commando is nu heel eenvoudig. + Schrijf een machinetaalroutine die u door een CALL commando + wilt laten aanroepen. U mag daarin de routines ILLEGA, + SYNTAX, R_BYTE en R_WORD gebruiken. Zorg dat bij het + verlaten van de routine HL wijst naar de positie na het + commando en dat de C vlag gewist is. Denk er verder om dat + de stack niet verandert ten opzichte van de situatie voordat + uw routine werd aangeroepen. + + Zet de standaardroutine erbij en zet het commando in de + tabel. De standaardroutine zorgt ervoor dat er alleen bij + het juiste CALL commando naar uw routine zal worden + gesprongen. + + Let erop dat het totale blok CALL commando's nooit meer kan + zijn dan 16 kB. Verlaag indien nodig de ORG &HC000. &H9000 + is in ieder geval altijd laag genoeg. U mag de BIOS routines + in page 0 en het systeem gebied in page 3 natuurlijk + gebruiken. + + Veel succes met het maken van uw eigen CALL commando's! + + Stefan Boer + \ No newline at end of file diff --git a/sunrise_special/3/memman_problemen.md b/sunrise_special/3/memman_problemen.md new file mode 100644 index 0000000..3cbfc2e --- /dev/null +++ b/sunrise_special/3/memman_problemen.md @@ -0,0 +1,242 @@ + M E M M A N + + I N T H E O R I E E N P R A K T I J K + + + I N L E I D I N G + + Onder MSX-DOS 1 laat het geheugenbeheer, met name bij + aanwezigheid van een memory mapper, veel te wensen over. Met + de komst van MSX-DOS 2 is dat sterk verbeterd, daar zitten + immers routines in om een pagina uit de memory mapper op te + roepen en weer vrij te geven. Volgens de deskundigen zit er + echter een bug in deze routines, waardoor eenmaal + opgevraagde pagina's nooit meer vrijgegeven kunnen worden, + tenzij de machine wordt gereset. + + Zo is MEMory MANager geboren. De programmeurs van MST hadden + de behoefte aan een stel goed werkende routines, waarmee het + gehele geheugen benut kan worden. Ze gingen echter verder. + Meerdere memory mappers, externe geheugen modules (16 & 64 + kB) en TSR's. Welnu over dit laatste onderwerp gaat dit + artikel. + + + W A T I S E E N T S R ? + + Gewoonlijk zal een programma na uitvoering niet in het + geheugen achterblijven. Programma's die dat wel doen, worden + aangeduid met de afkorting TSR: Terminate and Stay Resident. + Voorbeelden van dergelijke programma's zijn printerbuffers + en RAMdisks. Maar ook andere toepassingen, zoals een + rekenmachine of een kalender die met een toetscombinatie + opgeroepen kan worden, zijn denkbaar. + + In het verleden zijn TSR's voor de MSX een tamelijk zeldzaam + verschijnsel geweest. Het probleem was namelijk dat het + geheugen dat de TSR gebruikt, ook door andere programma's + gebruikt kan worden. Er zijn in een standaard MSX machine + geen mogelijkheden om een stuk geheugen voor een TSR te + reserveren. Dit probleem wordt door MemMan uit de wereld + geholpen. MemMan beheert het geheugen en zorgt er voor dat + er geen geheugenconflicten optreden. + + Dankzij MemMan is het mogelijk meerdere TSR's tegelijk in + het geheugen te hebben, waarbij elke TSR maximaal 16 kB + groot kan zijn. Op de standaard MSX is het laden van meer + dan ÇÇn TSR al lastig en alleen mogelijk als de TSR niet al + te groot is. Met de invoering MemMan krijgt de MSX betere + TSR mogelijkheden dan de alom gewaardeerde PC. Bovendien + doen ze niet onder voor de 'desktop accesoires' zoals die op + de Macintosh en de Atari ST gebruikt worden. + + Dit hoofdstuk is regelrecht overgenomen uit de handleiding + van MemMan, zoals die is geschreven door het MST. + + + N U D E P R A K T I J K + + Dat klinkt natuurlijk mooi, maar werkt het in de praktijk + ook zo soepel. Ik hoop in de rest van dit artikel een aantal + problemen boven water te halen, waaruit blijkt dat MemMan + heel leuk is, maar nog niet af. Daarentegen wil ik wel + iedereen blijven aanmoedigen om MemMan te blijven (of gaan) + gebruiken, want werken zonder MemMan is helemaal een gruwel. + + + P R O B L E E M 1 + + Een hoop bestaande programma's werken niet samen met MemMan + en profiteren dus niet van het bereikbaar worden van meer + geheugen. Bovendien werken veel programma's niet eens als + MemMan actief is. + + Het eerste gedeelte van het probleem is lastig op te lossen. + Het betekent dat ïf het programma herschreven moet worden, + ïf er moet een alternatief programma gebruikt worden, dat + wel met MemMan samenwerkt. + + Het tweede gedeelte van het probleem is veel leuker. Ook + hier herken je weer twee probleemgroepen. + + De eerste groep zijn de vastlopers. Als je je bedenkt dat + MemMan binnen de grenzen van de MSX standaard werkt, + betekent dit dat de vastlopende programma's dat dus niet + doen. Programma's die het gehele systeem voor zich opeisen + en denken dat ze ermee mogen doen wat ze willen. Helaas + bestaan ze. + + De tweede groep is het absolute toppunt voor m'n + lachspieren. Het programma geeft kort na het opstarten een + 'Not enough memory' error en het programma stopt. Het + probleem ligt hier in het TPA geheugen. + + Wat is TPA geheugen? Dat is de 64 kB die voor de processor + direct zichtbaar is. De rest van het geheugen is, net als + deze 64 kB, onderverdeeld in blokken van 16 kB. Door nu ÇÇn + van die blokken uit het TPA geheugen te verwisselen met een + blok uit de memory mapper, ziet de processor weer een ander + stukje data of programma. Om dit in goede banen te leiden is + MemMan ontwikkeld. Maar om goed te kunnen functioneren heeft + MemMan permanent een stukje geheugen nodig, zoals ook + MSXDOS(2).SYS en COMMAND(2).COM zich in dit geheugen + bevinden, maar ook de stack e.d.. Wat er nu nog overblijft, + is voor een in te laden programma en z'n te declareren + variabelen. Door MemMan is dat vrije TPA geheugen nu zo'n + 1,5 kB kleiner geworden. Voor sommige programma's genoeg + voor de eerder genoemde error. + + Dit laatste is alleen te verhelpen door het programma + opnieuw te compileren, met een verkleind vrij TPA geheugen. + Hiervoor heb je dan wel de source van het programma nodig en + dat is vaak een probleem. Als het om een commercieel pakket + gaat, is die source simpelweg onbereikbaar voor de + eindgebruiker. Het bedrijf wenst niet meer aan het programma + te sleutelen (veel voorkomend commentaar nu MSX commercieel + niet meer interessant is) en wil alleen voor grof geld de + source verkopen. Als het om een PD of shareware pakket gaat, + zou je de schrijver ervan kunnen benaderen met het eerder + genoemde verzoek. Sommigen zullen er gehoor aan geven + anderen niet. Persoonlijk vind ik dat elke programmeur hier + vooraf rekening mee moet houden en dus standaard met een + verkleind TPA geheugen moet compileren. + + Dit probleem is dus niet de schuld van de programmeurs van + MST. Programma's welke voor het MemMan tijdperk geschreven + zijn, kunnen moeilijk verweten worden dat ze niet met MemMan + samenwerken. Maar de overige moeilijkheden van dit probleem + zijn simpel te wijten aan het niet naleven van de standaard, + of het niet wensen rekening te houden met MemMan. Die + programmeurs welke in deze categorie thuis horen, zijn wat + mij betreft amateurs. + + Nvdr. Er is natuurlijk ook nog een categorie: programma's + waarvoor het samenwerken met MemMan onzin is. Bijv. spellen, + demo's en ook deze Special! Al zou de printerbuffer wel leuk + zijn bij het uitprinten. + + + P R O B L E E M 2 + + TSR's zijn vaak op te roepen d.m.v. een toetscombinatie. In + diverse programma's wordt ook gebruik gemaakt van een + toetscombinatie. Wanneer er een TSR actief is welke dezelfde + toetscombinatie gebruikt als een bepaalde functie uit het + lopende programma, heb je een probleem. Welke van de twee + wint nu het gevecht, het programma of de TSR. Oplossing + hiervoor is simpel. Toetscombinaties zijn voor TSR's. In een + normaal programma is het gebruik van toetscombinaties dus + uit den boze. + + Ook hier geldt hetzelfde als bij probleem 1. Programma's van + voor het MemMan en TSR tijdperk, kunnen dit niet verweten + worden. Maar programma's die ontwikkeld zijn toen MemMan en + TSR's wel reeds bestonden, hadden er rekening mee moeten + houden. De programmeurs van deze programma's zijn dus hier + egoãstisch bezig geweest. + + + P R O B L E E M 3 + + TSR's die elkaar in de haren vliegen, of de combinatie van + programma en TSR die elkaar niet liggen. Oorzaak: de al + eerder genoemde toetscombinaties, maar ook het actieve + SCREEN speelt een rol. Dit laatste punt heb ik lang over + nagedacht, maar ik denk dat hier, in tegenstelling tot de + andere moeilijkheden, een taak is weggelegd voor de + programmeurs van MemMan. + + Sommigen van jullie kennen ongetwijfeld de TSR Micro Music. + Deze TSR zet na een bepaalde toetscombinatie een menu op het + scherm. Welnu de programmeur heeft hier geen rekening + gehouden met het actieve screen en gaat er simpel vanuit dat + SCREEN 0 actief is. Gelukkig is hij niet de enige TSR + programmeur die deze fout maakt en het is dus ook geen + persoonlijke aanval op de programmeur van Micro Music. Deze + TSR wordt alleen als voorbeeld genomen. + + Maar ga eens in de positie van de programmeur staan. Eerst + uitzoeken welk SCREEN actief is, vervolgens kijken welk + gedeelte je daarvan wil gebruiken, dan de aanwezige info + ergens opslaan en de nieuwe info plaatsen. Bij het verlaten + van de TSR, moet dan de omgekeerde weg gevolgd worden. Als + je dan ook nog eens toevallig in een modem programma zit en + het scherm is constant aan verandering onderhevig, dan zijn + de rapen helemaal gaar. + + Het is dus veel eenvoudiger om te zeggen dat zo'n TSR alleen + werkzaam is in SCREEN 0. Sommige programmeurs kunnen dit + zelfs niet eens goed (Micro Music laat bij een actieve jANSI + een paar gekleurde blokjes zien boven in het scherm), maar + dat is een ander verhaal. MST zou hier kunnen helpen. + + Wanneer er in MemMan een routine zit, die voor TSR's een + universele manier aanbiedt voor het plaatsen van een + karakter op een op te geven positie op het scherm, ongeacht + welk SCREEN actief is en de oude informatie van die positie + bewaart, zijn we al een hele stap verder. Nu kan de + programmeur van een TSR simpel tegen MemMan zeggen: ik wil + dit karakter op die positie. Wanneer MemMan dan bijhoudt + welke posities gebruikt worden door de TSR, kan de + programmeur van de TSR voor het verlaten van de TSR deze + posities weer herstellen door aan MemMan de opdracht daartoe + te geven. + + De ideale oplossing voor bijna alle problemen. Veel + programma's wijzigen niets op het scherm, wanneer een TSR + actief is. Voor die gevallen dat zowel een programma als een + TSR actief zijn, die beiden het scherm geheel of + gedeeltelijk wijzigen, wordt het praktisch onmogelijk om dit + af te vangen. Die programma's die intensief met MemMan + samenwerken, zouden aan MemMan de door de TSR gebruikte + posities kunnen opvragen en deze dan niet gebruiken, maar + dat kan soms onoplosbare problemen met zich mee brengen. + Denk hierbij alleen maar aan de pulldown menu's e.d.. + + Dus de hier voorgestelde uitbreiding van MemMan is niet + alles dekkend, maar is een hele grote stap in de goede + richting. + + + C O N C L U S I E + + Wat is het leven met MemMan en speciaal hiervoor ontwikkelde + programma's toch een genot. Helaas laten diverse + programmeurs nog wel eens een steekje vallen. Wanneer ze de + inhoud van dit artikel nu eens als wet gaan beschouwen en + wanneer MST de voorgestelde uitbreiding van MemMan nu eens + bewerkstelligt, zijn we bijna waar we zijn moeten: + + Een systeem wat op een bijna optimale manier gebruik + maakt van alle mogelijkheden die het systeem bied. + + Tot slot nog ÇÇn extra opmerking voor de programmeurs. Wees + nu eens niet zo eigenwijs door er van uit te gaan dat de + aangesloten diskdrives A: en B: heten, maar vraag dit gewoon + aan het systeem. Harddisk gebruikers hebben A: en B: vaak in + gebruik als een partitie van de harddisk en de diskdrives + heten dan (in mijn geval) F: en G:. Maar het gebruik van + vele kopieerprogramma's is hierdoor niet meer mogelijk. + + Henk Hoogvliet + \ No newline at end of file diff --git a/sunrise_special/3/programmeren_sample_chip.md b/sunrise_special/3/programmeren_sample_chip.md new file mode 100644 index 0000000..7b11d53 --- /dev/null +++ b/sunrise_special/3/programmeren_sample_chip.md @@ -0,0 +1,176 @@ + P R O G R A M M E R E N S A M P L E C H I P + + + In deze tekst ga ik beschijven hoe je samples gemakkelijk in + BASIC of ML kunt gebruiken. Deze chip zit in de Music Module + van Philips, omgebouwde Toshiba modules en de standaard + MSX-AUDIO cartridges van Panasonic. + + + O U T C 0 H E N O U T C 1 H + + Met deze twee OUT's wordt de hele MSX-AUDIO bestuurd. Door + een getal op poort &HC0 te zetten kies je een register en + door op poort &HC1 een getal te zetten stuur je dat getal + naar het eerder gekozen register. + + + Een overzicht van de registers: + + Register 1: Niet gebruiken + + Register 2: Timer 1 preset. Beginwaarde N1 van Timer 1. + + Register 3: Timer 2 preset. Beginwaarde N2 van Timer 2. + + Register 4: Timer en Flag control. + Bit 0: "1" starten en "2" stoppen Timer 1. + Bit 1: "1" starten en "2" stoppen Timer 2. + Bit 2: niet in gebruik. + Bit 3: "1" maskeert Buffer Ready Flag. + Bit 4: "1" maskeert End of Sample Flag. + Bit 5: "1" maskeert Timer 2 Flag. + Bit 6: "1" maskeert Timer 1 Flag. + Bit 7: "1" reset alle Flags. + Bij het inschakelen van dit register worden bit 3 en 4 al + gemaskeerd. Bij het invoeren van de waarde &H78 in dit + register worden alle Flags gemaskeerd en bij het invoeren + van &H80 worden alle Flags gereset behalve de al eerder + gemaskeerde Flags. Voor meer informatie zie het Status + register. + + Register 7: ADPCM besturing. + Bit 0: "1" reset ADPCM functies. + Bit 1, 2, 3: niet in gebruik. + Bit 4: "1" herhaalt weergave sample. + Bit 5: "1" voor gebruik geheugen in module. + Bit 6: "1" opnemen en "0" weergeven. + Bit 7: "1" start opnemen of weergeven. + Bij invoeren van &HE0 kan er worden opgenomen en met &HA0 + weergegeven. Met "1" worden alle bits gereset. + + Register 8: Instellingen + Bit 0: Moet altijd op "0" worden gezet. + Bit 1: Moet altijd op "0" worden gezet. + Bit 2: "1" DA en "0" AD conversie. + Bit 3: "1" start en "0" stopt DA/AD conversie. + Bit 4, 5, 6: niet in gebruik. + Bit 7: "1" stelt CSM in. + Indien ADPCM mode gewenst is moeten alle bits "0" zijn. + + Registers 9 en 10: Startadres Sample. + Er is standaard 256 kB in blokjes van 32 kB RAM om te + samplen. Dus zijn er 256/32 = 8 van &H2000 bytes. De + adressen lopen dus van &H0000 tot &H1FFF. Als er een + geheugenuitbreiding aanwezig is, bijv. 1024 kB en er wordt + gesampled met een goed prgramma dat ook die 1024 kB gebruikt + zijn er 1024/32 = 32 van &H8000. De adressen lopen dan van + &H0000 tot &H7FFF. In register 9 komt de low-byte en in + register 10 komt de high-byte. Dus als het beginadres &H03FF + is dan zet je in register 9 &HFF en in register 10 &H03. + + Registers 11 en 12: eindadres. + Zie registers 9 en 10 alleen nu voor het eindadres. Bij 32 + kB is dat &H1FFF. In register 11 komt de low-byte en in + register 12 komt de high-byte. + + Registers 13 en 14: prescaler. + In deze registers komt een getal N te staan waarmee de + samplefrequentie Fs wordt bepaald door de klokfequentie van + 3580 kHz te delen door N. De maximale samplefrequentie is 16 + kHz en de minimale samplefrequentie is 1.8 kHz. + + Opname Frequentie | N | Register 13 | Register 14 + -------------------+-----------+--------------+------------- + 1.8 kHz | &H7FF | &HFF | 7 + 3 kHz | &H4A9 | &HA9 | 4 + 6 kHz | &H254 | &H54 | 2 + 10 kHz | &H166 | &H66 | 1 + 16 kHz | &H0E1 | &HE1 | 0 + ------------------------------------------------------------ + + Register 15: ADPCM-data. + Dit register is een buffer voor de ADPCM data van en naar de + computer. Dit register kan geschreven en gelezen worden. + Elke byte bevat 2 ADPCM samples die maar 4 bits (ÇÇn nibble) + bevatten. Als de high-nibble sample nummer "n" bevat dan + bevat de low-nibble het sample nummer "N+1" + + Registers 16 en 17: ADPCM weergave. + Deze registers bevatten de snelheid van de ADPCM weergave, + oftewel de afspeelfrequentie. + + Weergave frequentie | register 16 | register 17 + ----------------------+-----------------+------------------- + 1.8 kHz | &HF4 | &H08 + 3 kHz | &H5D | &H0F + 6 kHz | &HBA | &H1E + 10 kHz | &H36 | &H33 + 16 kHz | &HF0 | &H51 + 50 kHz | &HFF | &HFF + ------------------------------------------------------------ + + Register 18: volume weergave ADPCM. + Met dit register kan het volume van de weergave van de ADPCM + worden ingesteld. Met &HFF staat het volume voluit en met + &H00 is het geluid op zijn zachtst. Dit register kan goed + gebruikt worden voor fade ins en outs. + + Registers 19 en 20: ADPCM. + Deze twee registers bevatten de ADPCM-codering en + -decodering. + + Registers 24 en 25: Output control. + Met deze registers kan het geluid aan- en uitgezet worden. + In register moet altijd "8" staan om outputpoort 3 te + kiezen. Wanneer in register 25 het getal "8" wordt gezet + gaat het geluid aan en wanneer er "0" wordt gezet gaat het + geluid uit. + + Register 26: PCM-data. + Bufferregister voor AD en DA conversie, de data wordt hierin + opgeslagen in 2-complement vorm. + + + H E T S T A T U S R E G I S T E R + + Dit register kan gelezen worden zonder dat er eerst een + register moet worden aangeroepen. + + Bit 0: dit bit is "1" tijdens ADPCM opname/weergave. + Bit 1 en 2: zijn niet in gebruik en staan op "1". + Bit 3: deze Flag wordt op "1" gezet als de + datatransport klaar is. + Bit 4: Als het opnemen of afspelen klaar is wordt + dit bit gezet. + Bit 5: Gezet als Timer 2 "0" is. + Bit 6: Gezet als Timer 1 "0" is. + Bit 7: Dit bit wordt gezet als bits 3, 4, 5 en 6 + gezet zijn, er wordt dan een interrupt + veroorzaakt. De computer kan dan zien of de + interrupt veroorzaakt werd door de + soundprocessor. + + + H E T I N V O E R E N + + Dan nu hoe je al deze registers kunt programmeren. Zoals ik + al eerder heb geschreven doe je dit met OUT &HC0,register en + met OUT &HC1,waarde die naar het register moet. + + Dus als je het volume voluit wilt zetten doe je: + OUT &HC0,18:OUT &HC1,&HFF + + Zelf sample ik het liefst in MoonBlaster en daarna schrijf + ik die sample(s) weg om ze vervolgens in BASIC in te laden + met de MB BASIC routines. + + Nu begrijp je misschien waarom het makkelijk is de sample(s) + aan te kunnen sturen. Veel mensen die alleen de een sample + aan willen sturen maken een songfile waarbij ze dan precies + timen wanneer zo'n sample afgespeeld moet worden. In het + softwaremenu staat een programma om samples op te nemen en + af te spelen. + + Bart Schouten + \ No newline at end of file diff --git a/sunrise_special/3/scrollen_in_kun_basic.md b/sunrise_special/3/scrollen_in_kun_basic.md new file mode 100644 index 0000000..b1c5a63 --- /dev/null +++ b/sunrise_special/3/scrollen_in_kun_basic.md @@ -0,0 +1,72 @@ + S C R O L L I N G I N K U N - B A S I C + + + Zo, nu gaan we weer eens terug naar het begin: BASIC! Ik heb + namelijk een horizontale scroll gemaakt, geheel an al in + BASIC geschreven! Geen bitje machinetaal! (Nou ja, die ene + sprong naar adres &H69 niet meegerekend, dat is om eventueel + aanwezige sprites te wissen. Die routine staat gewoon in het + BIOS.) Het enige wat je nodig hebt is KUN-BASIC, oftewel + XBASIC. + + Kijk maar eens in de listing hoe ik het precies gedaan heb. + De truuk is: VDP(19) en het gebruik maken van integer + variabelen. + + + V D P R E G I S T E R 1 8 + + Zo! Hier ben ik nog eens met wat aanvullende info over de + super-scroll in BASIC. Zoals eerder vermeld heb ik gebruik + gemaakt van VDP register 18 (VDP(19)) Dit register wordt ook + gebruikt met het commando SET ADJUST (X,Y). Het is ook + mogelijk om met dit register verticaal te scrollen, maar dat + zou niet slim zijn, want met register 18 kun je dan over + slechts 16 pixels scrollen. vdp register 23 (VDP(23)) is dan + een beter alternatief, omdat dat register, nou ja, laat ik + maar zeggen, speciaal gemaakt is om verticaal te scrollen: + alle 8 bits worden gebruikt voor die ene richting: + verticaal. Je kunt zo dus heel eenvoudig en snel verticaal + scrollen, over 255 beeldlijnen (ja! Onder het scherm zit + namelijk ook nog het gedeelte waar de sprites, kleurwaardes + e.d. opgeslagen zijn, maar die zie je normaal niet). + Voorbeeld in de listing ALPHA.BAS in de laatste regels. + + Nu even terug naar register 20. Zoals gezegd worden 4 bits + voor de verticale en 4 bits voor de horizontale + positionering gebruikt. Scrollen bestaat dus eigenlijk uit: + 1 keer per interrupt 1 pixel "opschuiven" en in de tijd dat + je zo 16 pixels laat opschuiven, ÇÇn keer het hele + beeldscherm m.b.v. het COPY-commando kopieert. Et voilÖ! Een + mooie horizontale scroll! + + + P R O B L E E M P J E + + Nou is er nog een probleempje met de ietwat vreemde + programmering van het register: als je netjes 16 pixels wilt + scrollen, moet je eerst de waardes 8 t/m 15 invoeren, en + daarna pas 0 t/m 7, anders klopt er niet zoveel van. + + Zo, dat was het wel, ik hoop dat BASIC-programmeurs en ook + wel ML-programmeurs in spÇ hiermee wel vooruit kunnen. Voor + voorbeelden kijk je maar in de listing. + + Och, voor ik het vergeet: ik gebruikte wel het woord + interrupt, maar daarmee bedoel ik de tijd die de VDP nodig + heeft om een beeld op te bouwen, normaal dus 1/50 seconde + (of 1/60 bij Japanse computers). Om mooi die tijd aan te + houden, gebruik ik de TIME variabele, deze wordt namelijk + door de VDP met een opgehoogd, als de VDP klaar is met het + opbouwen van een beeld, dus elke 1/50 seconde. + + Volgende keer heb ik misschien een mooi programma (in + BASIC!) om zelf vector-graphics te maken. Een programma + waarmee je in principe elk willekeurig 3-dimensionaal object + kunt invoeren, en dan in elke richting kunt laten draaien, + verplaatsen, vergroten e.d. Lijnen die dan (gedeeltelijk) + buiten het beeld vallen worden geclipt: ze worden dan toch + goed getekend!! + + Randy Simons + \ No newline at end of file diff --git a/sunrise_special/3/tsr_change_cpu.md b/sunrise_special/3/tsr_change_cpu.md new file mode 100644 index 0000000..3f36587 --- /dev/null +++ b/sunrise_special/3/tsr_change_cpu.md @@ -0,0 +1,236 @@ + + C H A N G E C P U 2 + + + Naar aanleiding van de bespreking van de TSR Development Kit + volgt hier uitleg bij een source van een TSR. + + + N A A M G E V I N G + + TsrName: MACRO + DB "Ntm CHGCPU 2" + ENDM + + Deze TSR heb ik CHGCPU 2 genoemd omdat CHGCPU al bestond. + Met dat programma - van Ramon van der Winkel - kun je van + processormode wisselen met de HAI en IIE toetsen die naast + de spatiebalk zitten. Mijn programma gebruikt echter het + schakelaartje naast reset, dat verder alleen bij het + opstarten wordt gebruikt. + + Het is gebruikelijk om de initialen van je naam op de eerste + drie of vier plaatsen te zetten. Ntm is een afkorting voor + Nuthemagic (ja, nieuwe naam bedacht). + + De tekst moet overigens PRECIES 12 karakters lang zijn, + anders kom je voor onherkenbare problemen te staan. Ik kwam + er zelf pas achter toen ik de handleiding van het pakket had + doorgelezen. Iets dat ik meestal pas doe als ik een + programma doorheb. + + + M E M M A N - F U N K T I E + + MemMan: MACRO @FNC + LD E,@FNC + CALL #4002 + ENDM + + Bij MemMan 2.42 is er de mogelijkheid bijgekomen om in een + TSR op naar adres #4002 te springen, i.p.v. het adres op te + vragen via een tijdrovende Extended BIOS CALL. + + + DB "MST TSR",13,10 ;TSR identifier + TsrName ;ID-Name + DB 26 ;End Of File + DW 0002 ;Header file versie, + ; MemMan 2.2 in dit + ; geval + DW Base ;Code base address + DW Init ;Init address + DW Kill ;Kill address + DW Talk ;TsrCall entry + DW TsrLen ;Programma code + ; lengte + DW IniLen ;Init code lengte + + Hierboven staan de verschillende adressen die voor TsrLoad + nodig zijn om de TSR goed in te kunnen laden. + + + T S R - C O D E Z E L F + + Hier volgt het programma zelf. Base is de eerste byte van de + code die in het geheugen moet blijven staan. Het + Init-gedeelte wordt namelijk verwijderd na gebruik. (Erg + milieuvriendelijk is het niet, hergebruik zou best mogelijk + zijn.) + + Base: ;Eerste byte code + Kill: ;Geen kill-routine + Talk: RET ;Geen driver-routine + + Program: EX AF,AF' ;Hier begint het + ; echte werk + + EX AF,AF' is noodzakelijk omdat register A na de CALL van + H.TIMI (#FD9F) nog wordt gebruikt door de BIOS. EX AF,AF' is + hier makkelijker dan PUSH en POP omdat je in register A' een + code voor de TSR afhandelingsroutine van MemMan mee kunt + geven: EndHook. Dan worden de TSR's die verder nog aan de + hook hangen niet meer aangeroepen. + + + LD A,5 + OUT (#E4),A ;Zet op ISS-read + IN A,(#E5) ;Read ISS-stand + AND #40 ;Alleen bit 5 + + Zie MSX-Mozaãk voor uitgebreide informatie over de + OUT-poorten van de turbo R. In ieder geval staat er nu #40 + in A als de schakelaar naar links staat en #00 als de + schakelaar rechts staat. + + + LD HL,SaveByte ;Vergelijk met oude + CP (HL) ; stand + JR Z,EndProgram ;Gelijk? Niks doen + LD (HL),A ;Bewaar nieuwe stand + + Als de oude stand gelijk is aan de nieuwe, wordt er naar het + einde van de hookverwerking gesprongen. Werken met HL is + hier handiger dan de waarde in een ander register zetten en + dan daarmee vergelijken. + + + XOR #40 ;Precies andersom + RLA ;Schuif bit naar + RLA ; goede plaats + RLA ;Eentje minder voor + RLA ; R800-ROM + OR #80 ;LEDje wisselen + + Hier wordt de accumulator even goedgezet voor CHGCPU van de + BIOS. Als je wilt dat er naar R800-ROM en niet naar + R800-DRAM moet worden geschakeld, moet je ÇÇn RLA weglaten. + Indien je prefereert dat de schakelaar rechts de Z80-mode + aanduidt, moet je XOR #40 weglaten. Als je dit zelf niet + kunt omdat je de TSR Development Kit niet hebt, kun je + natuurlijk altijd naar de postbus schrijven, dan zal ik het + wel doen en je de juiste TSR opsturen. + + + LD IX,#0180 ;CHGCPU + LD IY,(#FCC0) ;BIOS-slot in IYH + CALL #001C ;CALSLT + + Interslot call naar CHGCPU routine van BIOS. Zou zonder + problemen een gewone CALL kunnen zijn, maar ik vind dit + gewoon veiliger. + + + EndProgram: XOR A + EX AF,AF' + RET + SaveByte: DB 0 + + TsrLen: EQU $-Base + + XOR A is nodig om de flags voor de TSR afhandelingsroutine + van MemMan goed te zetten. EX AF,AF' zet de flags op de + juiste plaats en herstelt ook weer de accumulator voor de + BIOS. + + SaveByte is vervolgens een byte om de huidige stand in te + bewaren. TsrLen geeft de lengte aan van de echte TSR-code. + + + I N I T I A L I S A T I E + + Init: LD HL,tTsrName ;Pointer naar naam + MemMan 62 ;Get TSR ID: + JR NC,InitError ;Ja, print tekstje + + Als de naam al bestaat is de carry laag en wordt er dus naar + de error-routine gesprongen. + + + LD A,(#FCC1) ;BIOS-slot in A + LD HL,#2D ;MSXTYP + CALL #0C ;RDSLT + CP 3 ;Kleiner dan 3? + JR C,InitError ;Ja, print tekstje + + Hier wordt even getest of de computer wel een turbo R (of + hoger?) is. Zo nee, dan wordt er naar de error-routine + gesprongen. + + + LD A,%10 ;Beâindig met tekst + LD DE,tInit ;Pointer naar tekst + RET ;Terug naar TsrLoad + + Geef flags mee in A en pointer naar tekst als bit 1 gezet is + in register DE. + + + InitError: LD A,%11 ;Fout, met tekst + LD DE,NoTRTekst + RET C ;Turbo R fout? + LD DE,tDouble + RET + + Als de computer naar InitError springt omdat de TSR al in + het geheugen zit is de carry laag. Als de betreffende + computer geen turbo R is, is de carry hoog. Hiervan maak ik + gebruik om een zo kort mogelijk stukje code te krijgen. + + + tTsrName: TsrName + + tInit: DB 12,"Wissel tussen R800-DRAM-mode en " + DB "Z80-mode d.m.v. de schakelaar naast" + DB " de resetknop",13,10,10 + DB "Freeware, Nuthemagic 11/10/92" + DB 13,10,10,0 + + NoTRTekst: DB "Helaas, pindakaas, dit werkt alleen" + DB " op een turbo R.",13,10,10,0 + + tDouble: DB "Twee keer dezelfde " + DB "TSR installeren heeft geen zin!" + DB 13,10,10,0 + + IniLen EQU $-Init ;Lengte init-code + + De diverse teksten. IniLen is om de initialisatiecode te + verwijderen. + + + H O O K - T A B E L + + Hooks: DW HokTabLen + DW #FD9F ;Hook + DW Program ;Code horende bij + ; hook + HokTabLen: EQU $-Hooks ;Lengte van + ; hook-tabel + + Met de hook-tabel kun je aangeven welke hooks je wilt + afbuigen. Dit gaat dus echt heel erg simpel. + + De lengte van de hook-tabel wordt bepaald door van het + huidige adres ($) het beginadres van de hook-tabel af te + trekken. + + De source is alleen nuttig ter leringh ende vermaeck. + Slechts als je de TSR Development Kit koopt kun je de TSR + daadwerkelijk veranderen. Zie de betreffende tekst daarover + voor meer informatie. + + Uiteraard staat de TSR wel op deze disk. Veel plezier ermee! + + Kasper Souren + \ No newline at end of file diff --git a/sunrise_special/3/tsr_development_kit.md b/sunrise_special/3/tsr_development_kit.md new file mode 100644 index 0000000..45d595f --- /dev/null +++ b/sunrise_special/3/tsr_development_kit.md @@ -0,0 +1,91 @@ + + - MEMMAN - + + T S R D E V E L O P M E N T K I T + + + Producent : MSX Software Team + Computer : + M S X 2 (80 kB RAM) + Medium : 1 dubbelzijdige diskette + Leverancier: MCM's lezersservice + + + Een tijdje geleden alweer dat dit produkt voor het eerst + verkocht werd. Zolang geleden zelfs dat ik toen nog geen ML + kende. + Maar hier volgt alsnog de bespreking van dit MST-produkt. + + + H E T P A K K E T + + ...bestaat uit een handleiding en een disk. Veel tekst uit + de handleiding zullen de meeste kopers van het pakket al + hebben: documentatie van MemMan calls en het artikel over + interrupts dat al in MCM heeft gestaan. Nieuw zijn echter de + beschrijving van het maken van TSR's volgens de MemMan + standaard - toevallig het belangrijkste - en de sources van + de PB.TSR en PRINT.COM. + + + D I S K + + Op de diskette staat eveneens een groot aantal files die al + in het bezit zijn van potentiâle kopers. Alleen LT.COM, de + linker, en daardoor het belangrijkste stukje bitvolgorde op + deze disk, en de raamwerken voor TSR-listings voor M80 en + GEN80. Ook zijn er nog 2 batchfiles, maar dat mag niet + bijster interessant worden genoemd. + + Wat je op deze disk mist zijn de 2 sources die wel in de + handleiding staan geprint. Misschien is dit gedaan ter + voorkoming van het vrijkomen van versies met hele kleine + aanpassingen. + + + R E L - B E S T A N D E N + + De linker werkt alleen met relocatable files. Files die op + een door de gebruiker of een ander programma dan de + assembler op de juiste plaats te zetten zijn. Beschrijving + van deze REL-files is te vinden op Sunrise Special #1. + + Voor zover ik weet is het alleen met GEN80 en M80 mogelijk + om REL-files aan te maken. Bij M80 is het trouwens alleen + maar mogelijk om REL-files te produceren. WB-ASS2 gebruikers + worden hierdoor uitgesloten, maar dit is niet zo erg: GEN80 + is toch veel beter! + + De linker maakt van die REL-files TSR-files. Deze files zijn + mijns inziens gewoon veredelde REL-files. In zoverre + veredeld dat TsrLoad ze makkelijk in een MemMan segment kan + plaatsen. + + + Z E L F M A K E N + + Zelf een TSR maken is een koud kunstje met dit LinkTsr. In + je source geef je de hook(s) aan die wilt afbuigen en zet je + de code die aan die hook(s) komt te hangen. Je hoeft je + verder dus niet te bekommeren over het vrijmaken van ruimte + in de top van het geheugen en het correct afbuigen van de + hooks. + + Als voorbeeld staan CHGCPU2.TSR en VOLINMET.TSR met source + en uitleg op deze Special. + + + C O N C L U S I E + + Als je dit koopt moet je niet denken dat je iets nieuws in + handen krijgt. Het grote voordeel is dat je nu alles bij + elkaar hebt, in ÇÇn handleiding. Als je makkelijk TSR's wilt + maken, is het zeker aan te raden! Maar ook als je al je + eigen systeem hebt om TSR's te maken is het een aanrader: + het is wel zo leuk voor de gebruikers om een eigen versie Çn + een MemMan versie te verspreiden. + + Waarschuwing: alleen voor GEN80- en M80-gebruikers. + + Kasper Souren + \ No newline at end of file diff --git a/sunrise_special/3/tsr_volume_input_meter.md b/sunrise_special/3/tsr_volume_input_meter.md new file mode 100644 index 0000000..7136bd1 --- /dev/null +++ b/sunrise_special/3/tsr_volume_input_meter.md @@ -0,0 +1,316 @@ + - MEMMAN - + + V O L U M E I N P U T M E T E R + + + Naar aanleiding van de bespreking van de TSR Development Kit + volgt hier uitleg bij een source van een TSR. Het is beter + om eerst de tekst over CHGCPU2.TSR te lezen, want in deze + tekst ga ik er vanuit dat die tekst al gelezen is. + + + N A A M G E V I N G + + TsrName: MACRO + DB "Ntm VolInMet" + ENDM + + VolInMet is de afkorting voor Volume Input Meter. Deze TSR + gebruikt de PCM input om de 5 LED'jes als meter te + misbruiken. Ntm is uiteraard van Nuthemagic. + + + B E G I N V A N S O U R C E + + MemMan: MACRO @FNC ;Macro voor MemMan + LD E,@FNC ; funkties + CALL MemManEntry + ENDM + + DB "MST TSR",13,10 ;TSR identifier + TsrName ;ID-Name + DB 26 ;^Z + DW 0002 ;Header file versie + ; MemMan 2.2 in dit + ; geval + DW Base ;Code base adres + DW Init ;Init adres + DW Kill ;Kill adres + DW Talk ;TsrCall entry + DW TsrLen ;Programma code + ; lengte + DW IniLen ;Init code lengte + + + Base: EQU $ ;Eerste byte van + ; programma + + Dit hele stuk is al uitgelegd in de andere tekst. + + + K I L L - C O D E + + Kill: LD A,(CAPS) ;Lees voormalige + ; stand van CAPS in + OUT (#AA),A ;en zet het weer + ; goed + + LD A,15 ;Lees KANA stand in + OUT (#A0),A ; en herstel + LD A,(KANA) + OUT (#A1),A + + LD A,(R800nPAUSE) ;Herstel R800- en + LD (#FCB1),A ; PAUSE LED'jes + OUT (#A7),A + + CALL Drive_off ;Drive-LED'je uit + LD A,(Sound) + OUT (#A5),A + Talk: RET ;Geen driver routine + ; (Waarom twee keer + ; RET als ÇÇn keer + ; genoeg is?) + + + Bij de initialisatie-routine wordt de huidige stand van de + LED'jes ingelezen, en de LED'jes worden weer goed gezet bij + het verwijderen van de TSR. + + Een driver routine is niet nodig, dus daar staat gewoon RET. + + + H O O K - V E R W E R K I N G + + Program: PUSH AF ;Bewaar AF + CALL Sample ;Neem monster, + ; output in A + CALL ChangeLEDs ;Verander LED's + ; aan de hand van de + ; waarde in A + XOR A ;MemMan TSR handler: + EX AF,AF' ; doorgaan met hook- + POP AF ; verwerking + RET + + Lekker duidelijk programmeren! Er zullen wel geen vragen + ontstaan over bovenstaand stukje. + + + S U B R O U T I N E S + + ChangeLEDs: SUB 50 ;A kleiner dan 50? + JR C,Caps_off ;CAPS e.v. uit + + 50 aftrekken van A, als A kleiner is dan 50, ontstaat er een + carry en wordt alle LED'jes (te beginnen bij CAPS) uitgezet. + Ik gebruik in dit geval CP omdat de routines dan duidelijker + zijn, er staat nu overal SUB 50, i.p.v. CP 50, 100, 150 enz. + + + Caps_on: EX AF,AF' ;A veiligstellen + IN A,(#AA) ;Alleen CAPS-bitje + AND 191 ; aanpassen + OUT (#AA),A + EX AF,AF' + SUB 50 ;A kleiner dan 100? + JR C,Kana_off ;KANA e.v. uitzetten + + Kana_on: EX AF,AF' ;A bewaren + LD A,15 ;KANA LED'je + OUT (#A0),A ; aanzetten + IN A,(#A1) + AND 127 + OUT (#A1),A + EX AF,AF' + SUB 50 ;A kleiner dan 150? + JR C,Pause_off ;PAUSE e.v. uit + + Pause_on: EX AF,AF' ;A bewaren + LD HL,#FCB1 ;In HL is + ; makkelijker + LD A,(HL) ;In (#FCB1) staat + ; stand van PAUSE + ; en R800 LED + OR 1 ;PAUSE aan + LD (HL),A ;Terugzetten + OUT (#A7),A + EX AF,AF' + SUB 50 ;A kleiner dan 200? + JR C,R800_off + + R800_on: EX AF,AF' + LD A,(HL) ;HL is nog #FCB1 + OR 128 ;Idem, wel met R800 + LD (HL),A ; LED + OUT (#A7),A + EX AF,AF' + SUB 50 ;A kleiner dan 250? + JR C,Drive_off + + Drive_on: LD E,#14 ;Drive LED'je aan- + LD A,#8B ; zetten d.m.v. + LD HL,#7FF2 ; klooien in drive- + JP #0014 ; controller + ;Met dank aan Mr. X + ; (kweenie meer wie) + + Waarde #14 in slot 3.2 (#8B) op adres #7FF2 zetten. JP komt + i.p.v. CALL en RET. + + + Caps_off: IN A,(#AA) ;CAPS uit + OR 64 + OUT (#AA),A + + Kana_off: LD A,15 ;KANA uit + OUT (#A0),A + IN A,(#A1) + OR 128 + OUT (#A1),A + + Pause_off: LD HL,#FCB1 ;PAUSE uit + LD A,(HL) + AND 254 + LD (HL),A + OUT (#A7),A + + R800_off: LD A,(HL) ;R800 uit, HL + AND 127 ; staat nog goed! + LD (HL),A + OUT (#A7),A + + Drive_off: LD E,#04 ;Drive uit + LD A,#8B + LD HL,#7FF2 + JP #0014 + + Sample: LD B,250 + LD D,B + LD A,12 ;Opnemen + OUT (#A5),A + LD A,128+120 ;Grens + LD (#A4),A + + Startwaarde wordt op 250 gezet. Telkens als er een "aan" + binnenkomt, wordt dat getal met ÇÇn verminderd. + + + Sample_loop: IN A,(#A5) + AND #80 ;Bit 7 gezet? + JR NZ,Count ;Nee, dan aftrekken + DJNZ Sample_loop + LD A,D + RET + + Count: DEC D + DJNZ Sample_loop + LD A,D + RET + + CAPS: DB 0 ;Bytes om voormalige + KANA: DB 0 ; stand LED'jes in + R800nPAUSE: DB 0 ; te bewaren + Sound: DB 0 + + + MemManEntry: JP 0 ;Ingevuld door init. + + TsrLen EQU $-Base ;Lengte van TSR + + + I N I T I A L I S A T I E + + Init: LD A,(#FCC1) ;BIOS-slot + LD HL,(#002D) ;MSX-type + CALL #0C ;Readslot + CP 3 ;turbo R? + JR C,Error ;Nee he? Toch geen + ; simpele computer? + + Eerst bepalen of het wel een turbo R is. Hopelijk hebben de + toekomstige versies (al komen die er volgens mij nooit) ook + dezelfde LED'jes, die op dezelfde manier aangestuurd worden. + :-) + + + IN A,(#A5) + LD (Sound),A + IN A,(#AA) ;CAPS aan? + LD (CAPS),A + LD A,15 + OUT (#A0),A ;KANA aan? + IN A,(#A1) + LD (KANA),A + LD A,(#FCB1) + LD (R800nPAUSE),A + + Stand van LED'jes bewaren. + + + LD B,6 ;MemMan entry + ; opvragen + LD DE,256*'M' + 50 ;MemMan info funktie + CALL #FFCA ;via extended BIOS + ; hook + + LD (MemManEntry+1),HL ;Bewaar MemMan + ; entry + + LD HL,tTsrName ;Pointer naar TSR + ; naam + MemMan 62 ;TSR al aanwezig? + JR NC,Error + + LD A,%10 ;Tekstje printen + LD DE,tIntro ;Tekstpointer in DE + RET ;Terug naar TsrLoad + + Error: LD DE,tDouble + LD A,%11 ;Init mislukt, toch + ; tekst afbeelden + RET NC + + LD DE,tIntro + LD A,7 ;Ook introtekst + LD (tNoTurboR-1),A ; printen + RET + + Zelfde foefje als bij CHGCPU2. + + + tTsrName: TsrName ;Macro, zie boven + + tIntro: DB 12 + DB "Volume Input Meter",13,10 + DB "------------------",13,10,10 + DB "Misbruikt de 5 LED'jes van de MSX " + DB "turbo R als meter van het geluid!" + DB 13,10,10 + DB "Freeware door Nuthemagic op een" + DB " kille donderdagmiddag, 10 december " + DB "1992, luisterend naar een opname van " + DB "Rave Radio.",13,10,10 + DB "Mochten er vragen of opmerkingen zijn:" + DB 13,10 + DB "Sunrise BBS Nuth, 045-245910, 24 uur " + DB "per dag.",13,10,10,10 + DB 0 + tNoTurboR: DB "Minstens ÇÇn turbo R benodigd om deze" + DB " TSR te draaien.",13,10 + DB 13,10,10,10,0 + + tDouble: DB "Jammer, maar 2 keer laden lukt echt " + DB "niet, hoor.",13,10,10,0 + + IniLen: EQU $-Init ;Length of init-code + + Hooks: DW HokTabLen ;Lengte van + ; hook-tabel + DW #FD9F ;Hook + DW Program ;Programma aan hook + + HokTabLen: EQU $-Hooks ;Lengte van tabel + + Kasper Souren + \ No newline at end of file diff --git a/sunrise_special/3/turbo-r_systeemcounter.md b/sunrise_special/3/turbo-r_systeemcounter.md new file mode 100644 index 0000000..128a427 --- /dev/null +++ b/sunrise_special/3/turbo-r_systeemcounter.md @@ -0,0 +1,153 @@ + T U R B O R S Y S T E E M C O U N T E R + + + Beloofd is beloofd, ik zou nog een tekst schrijven over de + systeemcounter van de turbo R. + + + W A A R O M E E N C O U N T E R ? + + Waarom hebben de ontwerpers van de turbo R er een counter in + gezet? Het is bij software vaak nodig om zo nauwkeurig + mogelijk tijdsduren te kunnen meten. Bijvoorbeeld om iets te + timen. Bij de Z80 werd hiervoor gewoon de verwerkings- + snelheid van de Z80 zelf gebruikt. Bij de Z80 staat het + namelijk van elke instructie vast hoe lang de Z80 erover + doet, zodat je precies kunt uitrekenen hoe lang het + uitvoeren van een bepaald stukje code duurt. + + Bij de R800 is dat anders, zie het artikel op Sunrise + Special #1. De R800 wordt bijvoorbeeld sneller als alles + zich binnen dezelfde 256 bytes afspeelt, en bovendien is de + refresh anders geregeld. Bij de Z80 wordt er na elke + instructie een refresh gedaan, bij de R800 is dat 32 keer + per seconde. + + Door dit alles is tijdmeting op basis van klokpulsen bij de + R800 niet nauwkeurig. Vandaar dat er een systeemcounter in + is gezet. + + + 1 6 B I T S + + De systeemcounter is eigenlijk heel simpel, gewoon een 16 + bits tellertje dat op twee I/O poorten zit en hardwarematig + wordt verhoogd (dus onafhankelijk van of bijv. de interrupts + aan of uit staan, of er wordt geladen van disk, etc.). + + De frequentie van de counter, en dus van de low byte, is + precies ÇÇn veertiende deel van de snelheid van de Z80A + (3.58 MHz), ofwel 255682 Hz. De counter wordt dus elke 3.91 + microseconde (miljoenste seconde) verhoogd. + + De high byte loopt uiteraard op 1/256 van deze snelheid, dat + is 999 Hz. De high byte heeft dus een frequentie van + ongeveer 1 kHz. + + + I / O P O O R T E N + + De counter zit op de I/O poorten &HE6 en &HE7, waarbij &HE6 + de low byte is en &HE7 de high byte. Voor gebruik in BASIC + zijn deze counters gewoonweg te snel, maar voor gebruik in + ML zijn ze uitermate geschikt. + + De counter kan worden gereset (op 0 gezet) door een + willekeurige waarde te schrijven naar poort &HE6. Schrijven + naar poort &HE7 heeft geen enkele invloed. + + Beide poorten kunnen worden gelezen. Het gebruiken van beide + poorten tegelijk heeft een klein probleempje, ze gaan + namelijk zo snel dat het kan gebeuren dat de counters + verspringen net nadat je de eerste hebt gelezen. Stel je + lees poort &HE6 het eerst en daar staat een 255. De kans is + dan groot dat de counter vlak daarna wordt verhoogd, en je + leest dan bijvoorbeeld de waarde 18 bij poort &HE7. Dit moet + dan echter 17 zijn! + + + T O E P A S S I N G E N + + Er zijn natuurlijk vele toepassingen, maar de belangrijkste + is wel bij samplen. De samplechip heeft trouwens z'n eigen + counter, die echter maar 2 bits is en wordt gebruikt voor de + timing bij de _PCMPLAY/_PCMREC commando's in BASIC. Deze + counter loopt op de bekende 15.75 kHz, de snelheid bij een + _PCMxxx comando met snelheidsparameter 0. + + Als we een sample play of record routine in ML willen maken, + kunnen we beter van de low byte van de 16 bits counter + gebruik maken, omdat die veel nauwkeuriger is. + + De counter wordt ook veel gebruikt bij afspeelroutines van + muziek voor MSX-MUSIC en MSX-AUDIO. Bij deze chips moet er + namelijk bij het beschrijven van de registers steeds even + gewacht worden. Routines die voor de Z80 zijn geschreven + gebruiken dan bijvoorbeeld twee keer EX SP,(HL), maar dat + duurt bij de R800 te kort waardoor het mis gaat. + + + M O O N B L A S T E R + + Als voorbeeld hier even een klein stukje van de MoonBlaster + replay. De replay kijkt zelf of hij onder R800 draait, en + indien dat het geval is zal hij aangepaste routines + gebruiken om de registers van de MSX-MUSIC en MSX-AUDIO te + beschrijven. Als voorbeeld hier MSX-MUSIC. + + PAROUT: EX AF,AF + CALL TRBWT ; wacht indien nodig + LD A,C + OUT (&H7C),A ; selecteer register + IN A,(&HE6) ; lees counter + LD (RTEL),A ; sla waarde op + EX AF,AF + OUT (&H7D),A ; schrijf waarde + RET + + TRBWT: PUSH BC + LD A,(RTEL) ; stand counter bij vorige keer + LD B,A + TRBWL: IN A,(&HE6) ; lees counter + SUB B + CP 7 ; al minimaal 7 verhoogd? + JR C,TRBWL + POP BC + RET + + Door de routine TRBWT (TuRBo WaiT) wordt er gewacht totdat + de counter sinds de vorige keer dat er een register werd + beschreven 7 maal is verhoogd. De huidige waarde van de + counter wordt in (RTEL) opgeslagen voor de volgende keer dat + deze routine wordt aangeroepen. + + + B A S I C + + In BASIC kan de counter ook worden gebruikt, er is namelijk + een speciaal BASIC commando voor. Dit is echter wel een + simpel commando, het kan alleen maar wachten! Wat een humor. + Je koopt een snelle computer en ÇÇn van de nieuwe BASIC + commando's dient om te wachten! Enfin, de syntax van het + nieuwe commando is: + + _PAUSE(x) + + waarbij voor x een getal tussen 1 en 32767 kan worden + ingevuld. De computer zal dan wachten totdat de high byte + van de counter (frequentie ca. 1 kHz) het opgegeven aantal + stapjes is verhoogd. Hiermee kunnen we de dus tot op 1/1000 + seconde nauwkeurig wachten. Bijvoorbeeld: + + _PAUSE(1000) + + wacht precies een seconde (N.B. Eigenlijk moet dit 999 zijn, + want zoals we weten loopt de high byte van de counter op 999 + Hz.) + + Meer valt er eigenlijk niet over de counter te zeggen. Voor + langere tijdmeting is hij niet geschikt, want hij doet er + maar ruim een kwart seconde over om "klokkie rond" te gaan. + + Stefan Boer + \ No newline at end of file diff --git a/sunrise_special/3/turbo_pascal_patch.md b/sunrise_special/3/turbo_pascal_patch.md new file mode 100644 index 0000000..9f9463c --- /dev/null +++ b/sunrise_special/3/turbo_pascal_patch.md @@ -0,0 +1,76 @@ + T P A T C H 1 . 1 + + + Nieuw in deze versie: aanpassing heap adres + + TPATCH patcht Turbo Pascal 3.0A MSX programma's automatisch + voor het gebruik met de MST Memory Manager. MemMan TSR's + functioneren alleen correct als de stackpointer in RAM + pagina 3 staat. Turbo Pascal zet echter zelf een lokale + stack op, waarbij de stackpointer in pagina 1 of 0 terecht + kan komen. Dat kan tot een crash leiden. + + Het is weliswaar mogelijk met een debugger het + stackpointer-adres in TP-programma's aan te passen, maar dat + neemt veel tijd in beslag. Daarom is TPATCH geschreven. + TPATCH zet de stackpointer van het TP-programma automatisch + op het default adres (0C500H in de distributie-versie) of op + een adres dat als parameter in de commandline opgegeven is. + Versie 1.1 van TPATCH past bovendien de heap-pointer aan. + + + Turbo Pascal deelt programma's als volgt in: + + 00100H Start runtime + 020EAH Start programma + 0xxxxH Ruimte voor stack & heap + 0yyyyH Start data + 0zzzzH Eindadres programma + + Na het gebruik van TPATCH ziet de indeling er als volgt uit: + + 00100H Start runtime + 020EAH Start programma + 0xxxxH Loze ruimte (zo klein mogelijk houden) + 0yyyyH Start data + 0zzzzH Eindadres programma + 0zzzzH+1 Ruimte voor stack & heap + 0ssssH Opgegeven top van de stack + + + Doordat het heap-adres in de vorige versie niet werd + veranderd, gaf de MAXAVAIL functie verkeerde resultaten. Die + functie geeft namelijk het verschil weer tussen de adressen + waar stackpointer en heappointer zich bevinden. Wordt de + stackpointer BOVEN het programmagedeelte geplaatst, dan ziet + MAXAVAIL veel meer ruimte dan er is, en kan programmacode + overschreven worden. + + De ruimte die voorheen voor heap en stack gereserveerd werd, + dient nu zo klein mogelijk gemaakt te worden, door in het + compiler-Options menu van Turbo Pascal het eindadres zo laag + mogelijk te zetten (zodat nog nät geen memory overflow + ontstaat). Een bijkomend voordeel is dat de uiteindelijke + COM-file die Turbo Pascal aanmaakt kleiner wordt. + + Houd er bij het programmeren verder rekening mee, dat de + heap en stack voldoende ruimte moeten hebben. Maak + programma's niet te groot. Overlays gebruiken extra + heapruimte. + + + Het gebruik van TPATCH: + + TPATCH FILENAAM[.COM] [hhhh] + + Vul voor de hhhh het (hexadecimale) adres in waar de + stackpointer op moet komen te staan. Wordt alleen de + filenaam opgegeven, dan zet TPATCH de stackpointer op $C500. + Die zgn. 'default' waarde is aan te passen door met een + debugger of disk-editor (eenmalig) het programma TPATCH.COM + aan te passen. Op de adressen $102 en $103 (START+2 en + START+3) staat nu: 00 C5, zijnde $C500 in hexadecimale + notatie (LSB,MSB). Dat kan naar believen veranderd worden. + + Pierre Gielen + \ No newline at end of file diff --git a/sunrise_special/3/vdp_commando_registers.md b/sunrise_special/3/vdp_commando_registers.md new file mode 100644 index 0000000..64df29d --- /dev/null +++ b/sunrise_special/3/vdp_commando_registers.md @@ -0,0 +1,326 @@ + V D P C O M M A N D O R E G I S T E R S I N M L + + + Als extraatje bij de VDP cursus op herhaling deze keer een + tekst over het gebruik van de commando's van de VDP in ML, + met een zeer handige standaardroutine. + + De theorie die in deze tekst gebruikt wordt staat allemaal + in VDP cursus (op herhaling) deel 1 t/m 4, die resp. op + Sunrise Special #2 en deze Sunrise Special #3 zijn te + vinden. Ik zal daar hier dus weinig aandacht aan besteden. + + + I N D I R E C T + + U kunt de VDP een commando (copy, line, etc.) laten + uitvoeren door de registers R#32 t/m R#46 te beschrijven. + Zodra R#46 met de code voor het commando wordt beschreven, + zal de VDP het commando gaan uitvoeren. + + Was de VDP op dat moment echter nog met een ander commando + bezig, dan zal het in de soep lopen. Daarom moet altijd + eerst gecheckt worden of de VDP al klaar was met het vorige + commando, door bit 0 van statusregister S#2 te lezen. + + Het schrijven van 15 opeenvolgende registers gaat het + makkelijkst met de indirecte methode. Hierbij schrijven we + eerst het startregister naar R#17, en we sturen de data + daarna naar Port #3 (I/O adres &H9B). De waarde van R#17 zal + automatisch worden verhoogd. + + Het Z80 commando OTIR is hiervoor uitermate geschikt. Dit + commando stuurt B bytes uit het geheugen vanaf adres (HL) + naar poort (C). Hiervan zullen we in de routine dan ook + gebruik maken. + + Meer dan genoeg theorie, het is nu hoog tijd voor de + universele VDP commando routine. Ik heb hem vroeger DOCOPY + gedoopt, omdat hij het meest voor copy's wordt gebruikt, + maar dat is dus wel een beetje misleidende naam want hij kan + voor alle commando's worden gebruikt. Ik ben zo gewend + geraakt aan die naam dat ik hem ben blijven gebruiken. + + + D O C O P Y + + Hier komt de source, zoals gewoonlijk in mijn favoriete + assembler (WB-ASS2). + + ; DOCOPY + ; Voer VDP commando uit + ; In: HL=start data + ; Gebruikt: AF, AF', HL, BC + + DOCOPY: LD BC,&H0F9B + CALL VDPRDY + DI + LD A,32 + OUT (&H99),A + LD A,17+128 + OUT (&H99),A + EI + OTIR + RET + + Eerst wordt B geladen met de waarde 15 (we willen 15 + registers beschrijven) en C met &H9B (we willen naar poort + &H9B schrijven). Een LD BC,.. commando is korter en sneller + dan een LD B,.. en een LD C,.. commando. De routine VDPRDY + (VDP ReaDY) wacht tot de VDP klaar is met het uitvoeren van + een eventueel vorig commando dat nog bezig is. + + Vervolgens wordt het startregister naar R#17 geschreven. + Zoals gewoonlijk moeten de interrupts hierbij uit staan. De + interrupts staan ook bij de OTIR nog uit, want na een EI + duurt het nog een instructie voordat de interrupts weer aan + gaan! Dit is overigens niet strikt noodzakelijk, alleen als + er in de interrupt routine iets met de VDP gebeurt moeten + de interrupts bij de OTIR ook per se uit staan. Simpel hä? + Nu de routines VDPRDY en RDSTAT (die weer door VDPRDY wordt + aangeroepen) nog: + + + ; VDPRDY + ; Wacht tot VDP klaar is met command execute + ; Gebruikt: AF, AF' + + VDPRDY: LD A,2 + CALL RDSTAT + BIT 0,A + JP NZ,VDPRDY + + ; RDSTAT + ; Lees VDP statusregister + ; In: A=S# + ; Uit: A=data + ; Gebruikt: AF' + + RDSTAT: DI + OUT (&H99),A + LD A,15+128 + OUT (&H99),A + NOP + NOP + IN A,(&H99) + EX AF,AF + XOR A + OUT (&H99),A + LD A,128+15 + OUT (&H99),A + EI + EX AF,AF + RET + + + Dit is een bekende routine, dus verdere uitleg is hier + overbodig. De interrupts worden steeds even weer aangezet + tijdens het uitvoeren van VDPRDY, omdat anders bijvoorbeeld + de muziek gaat haperen. Het zou in principe ook mogelijk + zijn om S#2 constant te lezen, maar dan zouden de interrupts + uit moeten staan zolang het vorige commando nog niet + afgelopen is, en dat kan soms te lang duren. + + + P R A K T I J K + + Een praktijkvoorbeeldje maakt dit wat duidelijker. Stel we + willen het blok (0,0)-(49,99) op page 3 kopiâren naar + (20,70) op page 1 met een high speed copy (HMMM). Dit gaat + dan als volgt: + + COPY: LD HL,COPDAT + JP DOCOPY + COPDAT: DB 0,0,0,3 ; source + DB 20,0,70,1 ; destination + DB 50,0,100,0 ; grootte + DB 0,0,&HD0 ; HMMM + + Voor alle VDP commando's dus een blokje van 15 bytes maken, + het gaat het handigste als je het op bovenstaande wijze + indeelt. Je ziet dat de page nummers gewoon de high bytes + van de y coîrdinaten zijn, dus het opgeven van de page gaat + heel simpel. &HD0 is de code voor HMMM (high speed move VRAM + to VRAM). + + + H M M C + + Tot slot nog een voorbeeldje van een iets ingewikkelder + commando, namelijk HMMC. Dit is wel een zeer belangrijk + commando, omdat je hiermee een plaatje uit het RAM naar het + VRAM kunt kopiâren, waarbij dit plaatje een willekeurige + rechthoek mag zijn. Bij gewoon RAM naar VRAM kopiâren kun je + alleen een bepaald adresbereik van het VRAM vullen, nu dus + gewoon een rechthoek zoals bij een normale copy. + + De werking van HMMC wordt uitgelegd in deel 3 van de cursus. + In de voorbeeldroutine wordt er een zwart 8*8 blokje met een + witte letter A naar het scherm gekopieerd op positie + (124,102) op page 0, dit werkt zowel op SCREEN 5 als SCREEN + 7. Ik gebruik hier de procedure zoals omschreven in het VDP + Technical Databook, dezelfde procedure die ik ook bij HMMC + in VDP cursus deel 3 heb gezet. + + + LD A,(GRPDAT) + LD (COPDAT+12),A ; vul eerste byte alvast in + LD HL,COPDAT + CALL DOCOPY + + + Hier wordt het commando al naar de VDP gestuurd. De + grafische data staat van GRPDAT, je ziet dat hier de eerste + byte alvast wordt meegegeven bij het geven van het commando. + Dit is overigens verplicht. + + + DI + LD A,44+128 ; R#44, geen auto increment + OUT (&H99),A + LD A,17+128 + OUT (&H99),A + EI + + + We gebruiken nu weer indirecte adressering om de data naar + de VDP te sturen. De data moet namelijk steeds naar R#44 + worden geschreven. We kunnen de indirecte methode ook + gebruiken om steeds naar ÇÇn register te schrijven, waarbij + de auto increment van R#17 dus uit staat. Dit kan door bit 7 + van R#17 te zetten (in de routine ziet u dus 44+128 staan). + + + LD HL,GRPDAT+1 + COPY: LD A,2 + CALL RDSTAT + BIT 0,A + RET Z + BIT 7,A + JP Z,COPY + LD A,(HL) + OUT (&H9B),A + INC HL + JP COPY + + + Hier wordt volgens de gegeven procedure de data naar R#44 + geschreven. Steeds wordt S#2 gelezen. Bit 0 is CE (Command + Execute), als dat bit 0 is, is het commando klaar. Bit 7 is + TR, dat aangeeft of de VDP klaar is voor de volgende byte. + Zo nee, dan lezen we S#2 opnieuw, zo ja, dan sturen we de + volgende byte naar Port #3, en dus naar R#44. Dit wordt + steeds herhaald totdat het klaar is. + + + COPDAT: DB 0,0,0,0 ; source (hier niet gebruikt) + DB 124,0,102,0 ; destination + DB 8,0,8,0 ; grootte + DB 0,0,&HF0 ; HMMC + + + Het blokje met de 15 bytes. De eerste bytes worden hier niet + gebruikt, dus daar heb ik gewoon 0 voor ingevuld. Je zou + eventueel ook een aangepaste DOCOPY kunnen maken die 11 + bytes stuurt naar R#36-R#45, maar de tijdwinst die daarmee + behaald wordt is zo minimaal dat dat weinig nut heeft. + + Let op: de grootte wordt altijd in pixels aangegeven, dus + niet in bytes! Ons blokje van 8*8 is maar 4*8 bytes. Die + bytes volgen nu. Een 1 staat voor zwart, een F voor wit. Als + je goed kijkt kun je de hoofdletter A erin zien. Uiteraard + kan hier elke willekeurige data worden ingevuld, het gaat + hier alleen om het voorbeeld. + + + GRPDAT: DB &H11,&H1F,&H11,&H11 + DB &H11,&HF1,&HF1,&H11 + DB &H1F,&H11,&H1F,&H11 + DB &HF1,&H11,&H11,&HF1 + DB &HF1,&H11,&H11,&HF1 + DB &HFF,&HFF,&HFF,&HF1 + DB &HF1,&H11,&H11,&HF1 + DB &HF1,&H11,&H11,&HF1 + + + K A N H E T N I E T S N E L L E R ? + + Dit werkt uitstekend, maar je vraagt je toch af: kan het + niet sneller? Dit was de procedure zoals die wordt + voorgeschreven door het Technical Databook, maar volgens mij + mag het ook op onderstaande manier. Het werkt in ieder geval + prima. + + Het blijkt namelijk dat de VDP de data die naar R#44 wordt + geschreven behoorlijk snel kan verwerken (Nvdr: misschien is + de R800 of de Z80 wel te langzaam), waardoor het helemaal + niet nodig is om TR steeds te checken. En CE checken is al + helemaal onzin, we weten immers wel hoeveel bytes we moeten + sturen. Dan kun je het ook als volgt programmeren: + + LD A,(GRPDAT) + LD (COPDAT+12),A ; vul eerste byte alvast in + LD HL,COPDAT + CALL DOCOPY + DI + LD A,44+128 ; R#44, geen auto increment + OUT (&H99),A + LD A,17+128 + OUT (&H99),A + EI + + + Tot hier is het exact hetzelfde. Nu komt het gedeelte dat is + veranderd: + + + LD HL,GRPDAT+1 + LD BC,&H1F9B ; 31 bytes naar port #3 + OTIR + RET + + + Dat is alles! (Ik laat COPDAT en GRPDAT nu achterwege, zijn + toch hetzelfde.) We moesten in totaal 4*8=32 bytes sturen, + waarvan er ÇÇn al is verstuurd bij het geven van het + commando. Die bytes moeten naar Port #3 worden gestuurd, + ofwel I/O poort &H9B. De data staat vanaf GRPDAT+1 (we + hadden de eerste byte immers al verstuurd), dus is een OTIR + voldoende! Bij copy's groter dan 256 bytes kun je OTIR + natuurlijk niet gebruiken, maar dat kan als volgt worden + opgelost: + + LD HL,GRPDAT+1 + LD BC,aantal bytes + COPY: LD A,(HL) + OUT (&H9B),A + INC HL + DEC BC + LD A,B + OR C + JP NZ,COPY + + + Als je 'normaal' RAM naar VRAM wilt verplaatsen, zet je + eerst de VDP klaar om VRAM te schrijven vanaf het gewenste + adres, en daarna stuur je de data naar Port #0 (&H98). + + Op de 'copy manier' (met HMMC dus) gaat het dus net zo snel, + en het werkt analoog. Eerst de VDP een HMMC klaar zetten om + de data te ontvangen (het HMMC commando geven met DOCOPY) en + daarna de data naar Port #3 schrijven (&H9B). Het voordeel + hiervan is dat je nu niet tot een bepaald adresgebied + beperkt bent. Als je bijvoorbeeld het gebied (100,100)- + (199,199) met data uit het RAM zou willen vullen, zou je bij + de 'normale' manier voor elke lijn opnieuw de VDP in moeten + stellen, terwijl dat met HMMC niet nodig is. + + HMMC is dus een zeer handig commando, vooral als je in een + programma een keer VRAM te kort komt. Je kunt de gewenste + graphics dan steeds razendsnel met HMMC uit het RAM halen. + + Veel succes met je eigen VDP routines en tot de volgende + keer! + + Stefan Boer + \ No newline at end of file diff --git a/sunrise_special/3/vdp_cursus_3.md b/sunrise_special/3/vdp_cursus_3.md new file mode 100644 index 0000000..3e810ce --- /dev/null +++ b/sunrise_special/3/vdp_cursus_3.md @@ -0,0 +1,274 @@ + M S X 2 / 2 + V D P C U R S U S ( 3 ) + + + + D E C O M M A N D O R E G I S T E R S + + Zoals beloofd behandelen we deze keer de commando registers. + Hiermee kunt u de VDP laten kopiâren, lijnen trekken, etc. + Nu volgt eerst een overzicht van de commando's, logische be- + werkingen en commando registers. + + + O V E R Z I C H T + + Naam: Doel: Bron: Eenh: Mnemonic: CM3 CM2 CM1 CM0 + ----------------------------------------------------------- + High- VRAM CPU Byte HMMC 1 1 1 1 + Speed VRAM VRAM Byte YMMM 1 1 1 0 + Move VRAM VRAM Byte HMMM 1 1 0 1 + VRAM VDP Byte HMMV 1 1 0 0 + Logical VRAM CPU Dot LMMC 1 0 1 1 + Move CPU VRAM Dot LMCM 1 0 1 0 + VRAM VRAM Dot LMMM 1 0 0 1 + VRAM VDP Dot LMMV 1 0 0 0 + Line VRAM VDP Dot LINE 0 1 1 1 + Search VRAM VDP Dot SRCH 0 1 1 0 + Pset VRAM VDP Dot PSET 0 1 0 1 + Point VDP VRAM Dot POINT 0 1 0 0 + Invalid 0 0 1 1 + Invalid 0 0 1 0 + Invalid 0 0 0 1 + Stop STOP 0 0 0 0 + ------------------------------------------------------------ + + Het commando wordt uitgevoerd door de VDP door de juiste + waarde van CM3-CM0 naar R#46 te schrijven. De juiste data + moet echter eerst naar R#32-R#45 worden geschreven (zie + verderop). Bit 0 van S#2 (CE = Command Execute), heeft de + waarde 1 als het commando wordt uitgevoerd, en de waarde 0 + als het klaar is. De werking van deze commando's is alleen + gegarandeerd in de modes G4-G7 (SCREEN 5 t/m 8, op MSX2+ + natuurlijk ook in SCREEN 10 t/m 12). Gebruik STOP om een + commando af te breken dat wordt uitgevoerd. + + + L O G I S C H E O P E R A T I E S + + Naam: Werking: LO3 LO2 LO1 LO0 + ----------------------------------------------------------- + IMP DC=SC 0 0 0 0 + AND DC=SC*DC 0 0 0 1 + OR DC=SC+DC 0 0 1 0 + EOR DC=NOT(SC)*DC+SC*NOT(DC) 0 0 1 1 + NOT DC=NOT(SC) 0 1 0 0 + TIMP if SC=0 then DC=DC else IMP 1 0 0 0 + TAND if SC=0 then DC=DC else AND 1 0 0 1 + TOR if SC=0 then DC=DC else OR 1 0 1 0 + TEOR if SC=0 then DC=DC else EOR 1 0 1 1 + TNOT if SC=0 then DC=DC else NOT 1 1 0 0 + ----------------------------------------------------------- + + SC = Source Color (bron), DC = Destination Color (doel). EOR + is hetzelfde als XOR in BASIC. De logische operaties mogen + worden toegepast bij LINE, PSET en LOGICAL MOVE commando's. + De juiste waarde van LO3-LO0 moet gelijktijdig met het + commando naar R#46 worden geschreven. + + + H E T C O O R D I N A T E N S Y S T E E M + + De VDP werkt met een ander coîrdinatensysteem dan MSX-BASIC. + Alle pages worden als het ware aan elkaar geplakt tot ÇÇn + groot scherm, waarbij de Y-coîrdinaten gewoon doorlopen. In + onderstaand overzicht is te zien hoe dat werkt. In het + midden staan de corresponderende adressen in het VRAM. + + G4 (SCREEN 5) Adres: G5 (SCREEN 6) + + -------------------------- 00000H -------------------------- + (000,000) (255,000) (000,000) (511,000) + Page 0 Page 0 + (000,255) (255,255) (000,255) (511,255) + -------------------------- 08000H -------------------------- + (000,256) (255,256) (000,256) (511,256) + Page 1 Page 1 + (000,511) (255,511) (000,511) (511,511) + -------------------------- 10000H -------------------------- + (000,512) (255,512) (000,512) (511,512) + Page 2 Page 2 + (000,767) (255,767) (000,767) (511,767) + -------------------------- 18000H -------------------------- + (000,768) (255,768) (000,768) (511,768) + Page 3 Page 3 + (000,1023) (255,1023) (000,1023) (511,1023) + -------------------------- 1FFFFH -------------------------- + + G7 (SCREEN 8) G6 (SCREEN 7) + + -------------------------- 00000H -------------------------- + (000,000) (255,000) (000,000) (511,000) + Page 0 Page 0 + (000,255) (255,255) (000,255) (511,255) + -------------------------- 10000H -------------------------- + (000,256) (256,256) (000,256) (511,256) + Page 1 Page 1 + (000,511) (255,511) (000,511) (511,511) + -------------------------- 1FFFFH -------------------------- + + Op het scherm zijn 212 (of 192) lijnen van dezelfde PAGE te + zien. Welke dat zijn kunt u instellen met R#23. + + + P A G E S + + PAGEs werken ook anders in ML, er is geen SET PAGE commando + of iets dergelijks. De PAGE die wordt getoond kan worden + ingesteld met R#2. U kunt daarbij het volgende tabelletje + gebruiken: + + Page: 0 1 2 3 + R#2: &H1F &H3F &H5F &H7F + + Bij het schrijven van VRAM in ÇÇn van de pages moet u gewoon + het juiste adres instellen, zie hiervoor deel 2 van de + cursus (de bits in R#14 bepalen daarbij de page). + + Bij kopiâren, lijnen trekken, etc. is er voor de VDP + helemaal geen sprake van PAGEs. De coîrdinaten lopen zoals + in bovenstaand overzicht te zien is gewoon door. Om de VDP + iets in een bepaalde pagina te laten doen, moet gewoon de + juiste waarde bij de y coîrdinaat worden opgeteld. + + Voorbeeld: stel u wilt een lijn trekken op page 3, van (23, + 68) naar (203,176). Dat wordt dan (23,68+768) en (203,176+ + 768). Het is dus niet nodig R#2 hiervoor te veranderen. + + In de praktijk gaat het werken met pages heel gemakkelijk, + omdat het gewoon de high byte van de y coîrdinaat is. Bij de + standaardmethode om een commando naar de VDP te sturen die + we nog zullen behandelen wijst zich dat vanzelf. + + + C O M M A N D O R E G I S T E R S + + Hieronder volgt een schematisch overzicht van de registers, + zoals we gewend zijn op binair niveau. + + MSB 7 6 5 4 3 2 1 0 LSB + ------------------------------------------------------------ + R#32 SX7 SX6 SX5 SX4 SX3 SX2 SX1 SX0 Source X Low + R#33 0 0 0 0 0 0 0 SX8 Source X High + R#34 SY7 SY6 SY5 SY4 SY3 SY2 SY1 SY0 Source Y Low + R#35 0 0 0 0 0 0 SY9 SY8 Source Y High + + R#36 DX7 DX6 DX5 DX4 DX3 DX2 DX1 DX0 Dest. X Low + R#37 0 0 0 0 0 0 0 DX8 Dest. X High + R#38 DY7 DY6 DY5 DY4 DY3 DY2 DY1 DY0 Dest. Y Low + R#39 0 0 0 0 0 0 DY9 DY8 Dest. Y High + + R#40 NX7 NX6 NX5 NX4 NX3 NX2 NX1 NX0 Nr of dots X Low + R#41 0 0 0 0 0 0 0 NX8 Nr of dots X Hgh + R#42 NY7 NY6 NY5 NY4 NY3 NY2 NY1 NY0 Nr of dots Y Low + R#43 0 0 0 0 0 0 NY9 NY8 Nr of dots Y Hgh + + R#44 CH3 CH2 CH1 CH0 CL3 CL2 CL1 CL0 Color register + R#45 0 MXC MXD MXS DIY DIX EQ MAJ Argument reg. + R#46 CM3 CM2 CM1 CM0 LO3 LO2 LO1 LO0 Command register + ------------------------------------------------------------ + + + Ik zal nu alle commando's ÇÇn voor ÇÇn gaan bespreken. Omdat + dat veel ruimte in beslag neemt, zal het over twee delen + worden verdeeld. Opmerking vooraf: bit 5 van R#45 bepaalt of + het VRAM (0) of Expansion RAM (1) wordt gebruikt. + + + H M M C + + High Speed Move CPU to VRAM + + Dit commando doet ongeveer hetzelfde als COPY TO + (X,Y) in Basic. Het schrijft data van de CPU naar een + rechthoek. Geef met DX, DY, NX, NY, DIX en DIY de gewenste + rechthoek aan. DIX en DIY werken als volgt: + + DIX: 0 = naar rechts vanaf DX, 1 = naar links vanaf DX + DIY: 0 = naar onder vanaf DY, 1 = naar boven vanaf DY + + De data moet steeds naar R#44 worden geschreven. Schrijf bij + het geven van het commando alvast de eerste byte naar R#44. + De opbouw van R#44 verschilt per schermmode: + + G4, G6 (SC5,7): CR7 CR6 CR5 CR4 CR3 CR2 CR1 CR0 + linker pixel rechter pixel + + G5 (SC6) : CR7 CR6 CR5 CR4 CR3 CR2 CR1 CR0 + links midlinks midrechts rechts + + G7 (SC8) : CR7 CR6 CR5 CR4 CR3 CR2 CR1 CR0 + ÇÇn pixel + + Dit omdat de data per byte moet worden verzonden, en in G4- + G6 meer dan ÇÇn pixel in een byte wordt opgeslagen. Hierdoor + worden er ook bits van NX en DX verwaarloosd. In G5 bit 0 en + 1, in G4 en G6 alleen bit 0. + + Als alles goed is ingevuld, schrijf je de waarde 11110000B + naar R#46. Vervolgens moet steeds S#2 worden uitgelezen, en + gekeken worden of TR of CE gelijk zijn aan 0. + + MSB 7 6 5 4 3 2 1 0 + S#2 TR VR HR BD 1 1 EO CE Status reg. 2 + + De volgende byte mag naar R#44 worden geschreven als TR + gelijk is aan 1. Het commando is klaar als CE gelijk is aan + 0. + + In schema: + 1) Schrijf de juiste waardes naar R#36-R#45 + 2) Schrijf 11110000B naar R#46 + 3) Lees S#2 + 4) Als CE=0 dan is het klaar + 5) Als TR=0 dan 3 + 6) Schrijf volgende byte naar R#44 + 7) Ga naar 3 + + + Y M M M + + High Speed Move VRAM to VRAM, y only + + Dit commando verplaatst de rechthoek die wordt aangegeven + door DX, SY, NY, DIX en DIY en de rand van het scherm aan de + rechterkant (of linkerkant, als DIX=1) naar eenzelfde blok, + echter met Y-coîrdinaat DY. Omdat het met bytes gaat, worden + in G4-G6 weer dezelfde bits van de X-coîrdinaten verwaar- + loosd als bij HMMC. + + Instellen van het YMMM commando: + R#34 en R#35: y-coîrdinaat van bron + R#36 en R#37: x-coîrdinaat van bron än doel + R#38 en R#39: y-coîrdinaat van doel + R#42 en R#43: lengte van rechthoek in Y-richting + R#45 : bepaal richting en soort VRAM + + Schrijf 11100000B naar R#46 om het commando uit te voeren, + het is klaar als CE gelijk is aan 0. + + + H M M M + + High Speed Move VRAM to VRAM + + Dit is een van de meest gebruikte commando's. Het verplaatst + de rechthoek die wordt aangegeven door SX, SY, NX, NY, DIX + en DIY naar het punt DX,DY. Weer worden de laagste bits van + de X-coîrdinaten verwaarloosd in G4-G6. + + Het commando is te vergelijken met COPY (SX,SY)- STEP(NX,NY) + TO (DX,DY) in Basic, met het verschil dat hierbij de x- + coîrdinaat een veelvoud van 2 (G4, G6) of 4 (G5) moet zijn. + Het is daarom ook sneller. + + Instellen van het HMMM commando: + Schrijf de juiste waardes naar R#32-R#43 en R#45. + + Schrijf 11010000B naar R#46 om het commando uit te voeren, + het is klaar als CE gelijk is aan 0. + + In het volgende deel volgt de rest van de commando's. Tot + dan! + + Stefan Boer + \ No newline at end of file diff --git a/sunrise_special/3/vdp_cursus_4.md b/sunrise_special/3/vdp_cursus_4.md new file mode 100644 index 0000000..674ef1f --- /dev/null +++ b/sunrise_special/3/vdp_cursus_4.md @@ -0,0 +1,384 @@ + M S X 2 / 2 + V D P C U R S U S ( 4 ) + + + Het laatste commado dat ik de vorige keer heb behandeld was + HMMM. Voordat we verdergaan, eerst nog even iets anders. + + + V E R S N E L L E N + + Er zijn twee methodes om het uitvoeren van de commando's + door de VDP te versnellen. + + 1) Zet de sprites uit + Als bit 1 van R#8 gelijk wordt gemaakt aan 1, kan de tijd + die normaal voor het weergeven van sprites wordt gebruikt + nu gebruikt worden voor het uitvoeren van commando's. Dat + gaat daardoor nu sneller. + + 2) Zet het scherm uit + Als bit 6 van R#1 gelijk wordt gemaakt aan 0, kan de tijd + die normaal voor het weergeven van het scherm wordt + gebruikt nu gebruikt worden voor het uitvoeren van + commando's. Dat gaat daardoor nu sneller. + + U kunt dit bijvoorbeeld gebruiken bij flip-screens (wordt + veel bij MSX2 spellen gebruikt, er is geen scrolling maar + als je het scherm uitloopt wordt het even zwart, waarna + het volgende scherm wordt getoond). Je kunt het scherm + namelijk ook zwart maken door PAGE 1 zwart te maken en + die te tonen. De schermopbouw gaat echter sneller als u + bit 6 van R#1 gebruikt. + + Ik ga nu verder met het overzicht van alle commando's. + + + H M M V + + High-speed move VDP to VRAM + + Dit commando vult een bepaalde rechthoek met een bepaalde + kleur. Het doet dus hetzelfde als LINE,BF in BASIC. + + High speed betekent geen logische bewerking en transport per + byte. De uitvoering is daarom veel sneller. Het nadeel van + transport per byte is dat in SCREEN 5 en 7 (G4 en G6) de X + coîrdinaat een veelvoud moet zijn van 2, en in SCREEN 6 + (G5), de X coîrdinaat een veelvoud moet zijn van 4. + + De volgende registers hebben betekenis bij HMMV: + + NX: grootte van rechthoek in X richting R#40, R#41 + NY: grootte van rechthoek in Y richting R#42, R#43 + DX: X coîrdinaat R#36, R#37 + DY: Y coîrdinaat R#38, R#39 + DIX, DIY: richting R#45 + CLR: kleur R#44 + + Nadat bovenstaande data naar de juiste registers is + geschreven kan het commando worden uitgevoerd door de waarde + &B11000000 naar R#46 te schrijven. CE geeft aan of de VDP al + klaar is (=0) of niet (=1). + + Let op: R#44 bevat niet het kleurnummer, maar de byte die + geschreven moet worden. Bij SCREEN 5, 6 en 7 kun je dus + verticale strepen maken. Zie voor de opbouw van de byte het + commando HMMC in het vorige deel. + + + L M M C + + Logical move CPU to VRAM + + Dit commando verplaatst data van de microprocessor naar het + VRAM naar een bepaalde rechthoek. De data wordt per pixel + verstuurd, er kunnen dus logische bewerkingen worden + toegepast. Er zijn ook geen beperkingen op de x coîrdinaten. + + De volgende registers moeten eerst met de juiste waarden + worden gevuld: + + R#36, R#37: DX X coîrdinaat bestemming + R#38, R#39: DY Y coîrdinaat bestemming + R#40, R#41: NX grootte in X-richting + R#42, R#43: NY grootte in Y-richting + R#44 : data de juiste data + R#45 : DIX, DIY de juiste richting + + Daarna kunt u het commando laten uitvoeren door &B1011---- + naar R#46 te schrijven. Op de plaats van ---- kunt u de code + van de gewenste logische operatie schrijven (0000 is geen + logische operatie). + + De data wordt nu per pixel verzonden. Dat gaat als volgt: + + MSB 7 6 5 4 3 2 1 0 LSB + R#44 - - - - C3 C2 C1 C0 G4 en G6 + R#44 - - - - - - C1 C0 G5 + R#44 C7 C6 C5 C4 C3 C2 C1 C0 G7 en hoger + + Dit commando is de langzamere versie van HMMC. Er kunnen nu + echter wel logische bewerkingen worden gebruikt. Ook is elke + X coîrdinaat mogelijk. Ik geef ook weer het werkschema: + + 1 Stel de commando registers in + 2 Schrijf &B1011---- naar R#46 (logische bewerking op ----) + 3 Lees S#2 + 4 Als CE gelijk is aan 0, dan is het klaar + 5 Als TR gelijk is aan 0, dan is het verzenden nog niet + klaar, ga terug naar 3 + 6 Anders kan nu de data naar R#44 worden geschreven + 7 Ga verder bij 3 + + + L M C M + + Logical move VRAM to CPU + + Dit commando verplaatst data van een bepaalde rechthoek per + pixel naar de CPU. Het is onzin hierbij een logische + bewerking te gebruiken. + + De volgende registers moeten worden ingevuld: + + R#32, R#33: SX Bron X coîrdinaat + R#34, R#35: SY Bron Y coîrdinaat + R#40, R#41: NX Grootte van rechthoek in X richting + R#42, R#43: NY Grootte van rechthoek in Y richting + R#45 : DIY, DIX Richting + + Het commando wordt uitgevoerd door de waarde &B10100000 naar + R#46 te schrijven. De data kan dan uit S#7 worden gelezen. + Denk er daarbij om dat de data verschilt per screenmode. Het + overzicht is hetzelfde als de data die bij het vorige + commando naar CLR moest worden geschreven. Ik geef u voor de + duidelijkheid wederom een werkschema: + + 1 Lees S#7 + 2 Schrijf de juiste waardes naar de commando registers + 3 Schrijf &B10100000 naar R#46 + 4 Lees S#2 + 5 Als TR=0 dan transport nog niet klaar, ga naar 4 + 6 Lees S#7 en doe met de waarde wat u wilt + 7 Als CE gelijk is aan 0 is het commando klaar + 8 Ga anders naar 4 + + Let op: + TR moet op 0 worden gezet voordat het commando wordt + uitgevoerd. Daarom moeten eerst S#7 worden gelezen. Ook al + is de data naar S#7 geschreven en TR=1, zal daarna toch het + commando worden afgemaakt en zal CE gelijk worden gemaakt + aan 0. + + + L M M M + + Logical move VRAM to VRAM + + Het LMMM commando verplaatst de data van het aangegeven + rechthoekige stuk naar een ander rechthoekig stuk. Omdat dit + gaat in eenheden van pixels, kunt u logische operaties + gebruiken. Ook dit is een zeer veel gebruikt commando. + + De volgende registers moeten eerst van de juiste waarde + worden voorzien: + + R#32, R#33: SX Bron X coîrdinaat + R#34, R#35: SY Bron Y coîrdinaat + R#36, R#37: DX Doel X coîrdinaat + R#38, R#39: DY Doel Y coîrdinaat + R#40, R#41: NX Grootte X richting + R#42, R#43: NY Grootte Y richting + R#45 : DIX, DIY Richting + + Schrijf &B1001---- naar R#46 om het commando uit te voeren. + U kunt op de streepjes de gewenste logische bewerking + invullen. + + Dit commando wordt door MSX BASIC 2.0 en hoger gebruikt voor + COPY (SX,SY)-STEP(NX,NY) TO (DX,DY),,. + + + L M M V + + Logical move VDP to VRAM + + Dit commando doet hetzelfde als HMMV, met het verschil dat + er nu wel logische bewerkingen kunnen worden toegepast en + dat het transport nu met pixels in plaats van bytes gebeurt. + De X coîrdinaat kan dus elke waarde hebben. Het gaat daarom + ook langzamer. + + Dit commando wordt in MSX BASIC 2.0 en hoger gebruikt voor + LINE(DX,DY)-STEP(NX,NY),CLR,BF,. + + Voor de werking verwijs ik dus naar HMMV, er moet nu echter + &B1000---- naar R#46 worden geschreven, en op de laagste + vier bits de logische bewerking. Van de X coîrdinaat worden + alle bits behouden. + + + L I N E + + De naam zegt het al, met dit commando kunt u de VDP lijnen + laten trekken. Die lijn die wordt getekend is de schuine + lijn van een rechthoekige driehoek. (Dat is een driehoek + waarvan twee zijden loodrecht op elkaar staan.) De twee + rechthoekszijden worden aangegeven als afstanden vanaf ÇÇn + punt. (Dat is het punt waar de rechte hoek zit.) + + De volgende registers moet u beschrijven met de juiste + waardes: + + R#36, R#37: DX X coîrdinaat + R#38, R#39: DY Y coîrdinaat + R#40, R#41: MJ grootte van de langste zijde (NX) + R#42, R#43: MI grootte van de kortste zijde (NY) + R#45 : DIX richting van de rechthoekszijden + vanaf het punt (DX,DY) + 0: rechts 1: links + : DIY 0: omlaag 1: omhoog + : MAJ 0: lange zijde is X + 1: lange zijde is Y + R#44 : C Kleur (G4,G6 0-15; G5 0-3; G7 0-255) + + Schrijf &B0111---- naar R#46 om de lijn te trekken. Op de + streepjes kunt u een eventuele logische bewerking invullen. + + Dit is erg ingewikkeld. Zoals al eerder aangekondigd zullen + in latere delen van de VDP cursus vele toepassingen van het + geleerde behandeld worden, voorzien van zeer uitgebreide + uitleg. Daar zal ook zeker een routine voor lijnen bij + zitten. Voor de duidelijkheid geef ik u nu nog hoe het er in + BASIC uit zou zien: + + LINE (DX+MAJ,DY)-(DX,DY-MIN),C,,. + Hierbij zijn DIX, DIY en MAJ gelijk aan 0. + + Zoals gewoonlijk is CE van S#2 gelijk aan 1 als het commando + wordt uitgevoerd. + + + S R C H + + Het SRCH commando zoekt (search = zoeken) naar een pixel met + een bepaalde kleur naar de linker- of rechterkant van een + bepaald startpunt. Dit commando wordt bijvoorbeeld gebruikt + bij het PAINT commando van BASIC. + + De volgende registers worden door SRCH gebruikt: + + R#32, R#33: SX X coîrdinaat startpunt + R#34, R#35: SY Y coîrdinaat startpunt + R#44 C te zoeken kleur + R#45 : DIX Geeft zoekrichting aan (0 = rechts) + : EQ Geeft aan wanneer de VDP moet stoppen + met zoeken. 1 = stop als een pixel met + de juiste kleur is gevonden, 0 = stop + als een pixel met een andere kleur is + gevonden. + + Schrijf de waarde &B01100000 naar R#46 om het commando te + starten. De statusregisters worden als volgt beãnvloed: + + S#2 : BD Bit 4 wordt 1 als kleur gevonden + : CE Bit 0 wordt 0 als commando klaar + S#8 : BX X coîrdinaat van plaats waar gevonden + S#9 : BX Bit 0 bevat bit 8 van X coîrdinaat + Overige bits bevatten de waarde 1 + (bit 8 wordt alleen gebruikt bij G5 + en G6) + + Werkschema: + + 1) Schrijf de juiste waardes naar de commandoregisters + 2) Schrijf &B01100000 naar R#46 + 3) Lees S#2 + 4) Als CE=1 dan 3, commando nog niet klaar + 5) Als BD=0 dan klaar, kleur niet gevonden + 6) Lees S#8 en S#9 + 7) Klaar + + + P S E T + + Het PSET commando doet hetzelfde als PSET(X,Y),C, in Basic. Het zet een pixel in de kleur C op + positie (X,Y), daarbij wordt eventueel de logische bewerking + uitgevoerd met de pixel die er al stond. + + De coîrdinaten moeten in DX en DY staan, R#36-R#39. De kleur + kunt u in R#44 zetten. De volgende kleurnummers zijn + mogelijk: + + Mode: Kleurbereik: + ------------------------------- + SCREEN 5, G4 0-15 + SCREEN 6, G5 0-3 + SCREEN 7, G6 0-15 + SCREEN 8, G7 0-255 + + Schrijf de waarde &B0101---- naar R#46 om het PSET commando + uit te voeren. Op ---- kunt u eventueel een logische + operatie invullen. + + + P O I N T + + Dit commando doet het tegenovergestelde van PSET. Het leest + namelijk de kleur van een bepaald pixel. In BASIC hebben we + daarvoor het commando POINT(X,Y). + + De coîrdinaten moeten nu in SX en SY staan, R#32-R#35. De + kleur komt in S#7 te staan. Daarbij zijn dezelfde kleur- + nummers mogelijk als bij PSET. + + Schrijf de waarde &B01000000 naar R#46 om het POINT commando + uit te voeren. Het CE bit van S#2 zal tijdens het uitvoeren + van het commando de waarde 1 krijgen. Als het klaar is wordt + CE weer op 0 gezet. Dan kan S#7 worden uitgelezen. + + + N A E E N C O M M A N D O + + Dit was het einde van het overzicht van alle commando's. Tot + slot nog een overzicht van de beãnvloeding van de commando + registers door de verschillende commando's. Ofwel: hoe zien + de commandoregisters eruit als een commando is uitgevoerd. + + Het is namelijk niet nodig om alle registers steeds opnieuw + in te vullen. Sommigen behouden hun waarde. U kunt in de + tabel zien welke dat zijn. In de praktijk zullen meestal + toch alle commandoregisters worden beschreven. + + Uitleg bij de tabel: + + - Onveranderd + * Coîrdinaat aan het einde van commando (of kleurcode) + # De waarde die het register had toen het einde van het + scherm werd bereikt + + SX DY DX DY NX NY CLR CMRH CMRL ARG + ------------------------------------------------------------ + HMMC - - - * - # - 0 - - + YMMM - * - * - # - 0 - - + HMMM - * - * - # - 0 - - + HMMV - - - * - # - 0 - - + LMMC - - - * - # - 0 - - + LMCM - * - - - # * 0 - - + LMMM - * - * - # - 0 - - + LMMV - - - * - # - 0 - - + LINE - - - * - - - 0 - - + SRCH - - - - - - - 0 - - + PSET - - - - - - - 0 - - + POINT - - - - - - * 0 - - + ------------------------------------------------------------ + + N.B. De eindwaardes van SY, DY en NY (SY*, DY* en NYB) + moeten als volgt worden omgerekend: + + (DIY = 0) SY* = SY + N DY* = DY + N + (DIY = 1) SY* = SY - N DY* = DY - N + + NYB = NY - N + + Bij het LINE commando moet u nog 1 van N aftrekken als MAJ + gelijk is aan 0. + + + T O T S L O T + + Met deze theorie kunt u nu alle VDP commando's zelf + toepassen. Ik heb bij deze herhaling van de VDP cursus + echter nog een extra tekst geschreven, waarin wordt + uitgelegd hoe je de commando's het beste naar de VDP kunt + sturen, met een aantal voorbeelden. Dit staat in het submenu + onder de naam VDP CURSUS ML. + + De volgende keer zijn de statusregisters aan de beurt. Nadat + ook de sprites en de opslag van de scherminhoud behandeld + zijn zullen we een aantal zeer leuke toepassingen doornemen. + Veel succes en tot de volgende keer! + + Stefan Boer + \ No newline at end of file diff --git a/sunrise_special/3/werken_met_ascii_c.md b/sunrise_special/3/werken_met_ascii_c.md new file mode 100644 index 0000000..1e093ce --- /dev/null +++ b/sunrise_special/3/werken_met_ascii_c.md @@ -0,0 +1,167 @@ + H E T W E R K E N M E T A S C I I C + + + D E E L 1 + + DE VERSCHILLEN TUSSEN ASCII C 1.1 en ASCII C 1.2 + + + Zoals wellicht bekend, zijn er diverse C compilers voor de + MSX beschikbaar, waarbij Hisoft C en ASCII C de + uitgebreidste zijn. Mijn favoriete C compiler is die van + ASCII corporation, waarvan ik mijn gebruikerservaringen zal + bespreken. In dit eerste deel zal ik vooral proberen om de + verschillen tussen versie 1.1 en 1.2 aan te geven (het + belangrijkste verschil is dat versie 1.1 voor MSX-DOS 1 is, + terwijl versie 1.2 voor MSX-DOS 2 is). Hierbij ga ik er + vanuit dat de lezer de beschikking heeft over de handleiding + van versie 1.1. + + De C compiler van ASCII corporation bestaat uit een aantal + verschillende bestanden voor de verschillende delen van het + compilatie proces. Dit maakt het gebruik van deze compiler + relatief ingewikkeld, maar daar staat wel een zeer grote + flexibiliteit tegenover. + + De compiler bestaat ten eerste uit 2 hoofdprogramma's, + namelijk: CF.COM en CG.COM, dit zijn respectievelijk de code + parser en de code generator. + + + + C F . C O M , D E P A R S E R + + De parser leest de source file in, voert hier een + syntactische analyse op uit en genereert een tijdelijke file + waar de zogenaamde parse boom in wordt opgeslagen. Deze + parser is afgeleid van de Microsoft C compiler voor CP/M. + Bij het inlezen van de source file verwerkt de parser tevens + alle include commando's. Bij include zijn er 2 syntaxen, + hierbij komen de verschillen tussen C 1.1 en C 1.2 voor het + eerst duidelijk om de hoek: + + 'syntax' C 1.1 C 1.2 + include Haal de include file van Haal de include file + "filename" dezelfde drive als de van dezelfde drive + hoofd source file. als de hoofd source + file. + include Haal de include file van Haal de include file + de default drive. uit de directory die + in het environment + item INCLUDE staat. + + Bij C 1.2 kun je dus de standaard headerfiles in een aparte + directory zetten, wat je vervolgens onder DOS doorgeeft aan + de compiler met SET INCLUDE = include directory + + + C G . C O M , D E C O D E G E N E R A T O R + + De code generator leest de tijdelijke file in en zet de + parse informatie hieruit om in machinecode. Hierbij wordt + een assembler source file gemaakt in een formaat dat + geschikt is voor M80, de reloceerbare macro assembler van + Microsoft. Deze code generator voert tevens een + (uitschakelbare) register-optimalisatie uit. Hierdoor is de + gegenereerde code behoorlijk snel (ik heb bijv. een eigen + paint routine geschreven, eenmaal in C en ter vergelijking + ook eenmaal in assembler, de handgeschreven assembler versie + was maar 10% sneller dan de gecompileerde C versie), al + maakt deze optimalisatie het compilatieproces natuurlijk wel + een stuk trager. + + Ook deze code generator is afgeleid van de code generator + van de Microsoft C compiler voor CP/M. Dit laatste heeft 1 + klein nadeel: + + Aangezien de CP/M wereld veel Intel 8080 processors + (voorloper van de Z80) kende, maakt deze code generator code + aan voor deze Intel-processor. De Z80 heeft echter een + aantal uitbreidingen t.o.v. de 8080 die hierdoor niet benut + worden. Indien ASCII corporation de code generator dus echt + goed had aangepast, dan had de gecompileerde code nog iets + beter kunnen zijn. + + Ook bij het aanmaken van de code is er een klein verschil + tussen versie 1.1 en 1.2. De eerste versie maakt namelijk + Intel formaat mnemonics aan (niet te lezen voor de Z80 + programmeurs) terwijl de tweede versie Zilog formaat + mnemonics aanmaakt (let wel, de geproduceerde code is echter + nog altijd beperkt tot de 8080 subset). + + Behalve deze code omzetters (C source naar assembler + source), bestaat de compiler ook nog uit een aantal + standaard library's en een aantal header files voor deze + library's. Bij de C compiler worden de library's in 2 + formaten meegeleverd: + + 1) In het reloceerbare .REL formaat, zodat ze met L80 + meegelinkt kunnen worden. + 2) Als een aantal C en assembler source files zodat ze + eventueel aangepast kunnen worden voor speciale + toepassingen. + + Er zijn 4 reloceerbare files, waarbij er weer verschillen + zijn tussen de .REL files van versie 1.1 en versie 1.2: + + CK.REL: De zogenaamde kernel, deze code wordt uitgevoerd bij + het opstarten van een C programma. De kernel onderzoekt de + command line en springt vervolgens naar de routine "main" + toe. Bij versie 1.1 wordt bij het onderzoeken van de command + line tevens gecontroleerd op de symbolen > (redirection) en + | (pipelining), dit omdat MSX-DOS 1 geen redirection en + pipelining ondersteunt, terwijl een aantal C toepassingen + hier wel gebruik van maken omdat C uit de UNIX wereld komt + waar redirection en pipelining zo ongeveer zijn uitgevonden. + Versie 1.2 controleert hier niet meer op omdat MSX-DOS 2 dit + zelf doet. + + CRUN.REL: Hier zitten een aantal routines in die nodig zijn + bij een C programma, zoals het vermenigvuldigen, delen en + vergelijken van 16 bits getallen. Als er in de source file + bijv. staat: + + { + int a,b,c; + a = 3; b = 4; + c = a * b; + } + + dan maakt de compiler ervan: + + ld hl,3 + ld de,4 + call ?MULHD + + De routine MULHD is dan te vinden in CRUN.REL. Er is hierbij + geloof ik geen verschil tussen de 2 CRUN versies. + + CEND.REL: In deze file bevind zich het label @endx@ zodat + eventuele interne routines uit CK en CRUN weten tot waar het + programma loopt. + + CLIB.REL: Dit is de echte C library waar de standaard + functies in zitten. Hierbij zijn er wezenlijke verschillen + tussen versie 1.1 en versie 1.2, de eerste werkt bij de file + in/out namelijk overal met FCB's, terwijl de tweede overal + met de file handles van MSX-DOS 2 werkt. Het is hierom ook + belangrijk dat van CK.REL en CLIB.REL de goede versies bij + elkaar worden gebruikt, dit omdat CK een aantal standaard + devices opent voor functies zoals printf(). Bij CK 1.1 en + CLIB 1.1 worden hier dus FCB's voor gebruikt terwijl CK 1.2 + en CLIB 1.2 alles met de file handles doen. CK 1.2 + controleert tevens de DOS-versie zodat C programma's die + gelinkt zijn met deze versie een foutmelding geven als ze + onder MSX-DOS 1 worden opgestart. + + Behalve deze library's worden ook nog een aantal header + files meegeleverd waar alle relevante types in worden + gedefinieerd. Bij versie 1.2 zijn de header files een stuk + verder opgesplitst dan bij versie 1.1. Tevens zijn de + definities van sommige types veranderd, zo is bijv. het type + FILE veranderd omdat de routines uit CLIB hier andere + informatie in opslaan. Het is daarom belangrijk dat de + versie van de header-files overeenkomt met de versie van de + library's! + + Alex Wulms diff --git a/sunrise_special/4/BDOS foutafhandeling.md b/sunrise_special/4/BDOS foutafhandeling.md new file mode 100644 index 0000000..122d22c --- /dev/null +++ b/sunrise_special/4/BDOS foutafhandeling.md @@ -0,0 +1,186 @@ + B D O S F O U T A F H A N D E L I N G + + + Dit is een onderwerp waar ik nog nooit een artikel over heb + gezien, en onder het motto "Beter laat dan nooit" moet daar + nu maar eens verandering in komen. Dit artikel is bedoeld + voor diegenen die niet verwonderd kijken als de term BDOS + valt. + + De BDOS kent twee manieren om fouten af te handelen. De + meest bekende is die van het A register dat na een BDOS + aanroep met 0 of een andere waarde gevuld is. Is A=0, dan is + de BDOS aktie goed gegaan en in alle andere gevallen is er + iets mis gegaan. De tweede methode is wat onbekender. Onder + MSX-DOS zijn dit de fouten die een 'Abort, Retry, Ignore' + melding opleveren. Onder BASIC zijn dit de fouten waardoor + het lopende programma onderbroken wordt (ook machinetaal + programma's) en naar BASIC teruggekeerd wordt. + + De eerste methode is bij alle BDOS gebruikers bekend, maar + de tweede roept vaak vele vraagtekens op (zelfs bij mij). + Dat komt in de eerste plaats omdat ik zo goed als geen + documentatie bezit over deze methode, maar dat merkt u + straks nog wel. U moet me dus maar vergeven dat ikzelf hier + en daar ook nog wat vragen open laat omdat ik simpelweg niet + over de documentatie beschik om alles tot in perfektie te + behandelen. Als er dus mensen zijn die de door mij + onbeantwoorde vragen wel kunnen beantwoorden, dan zou ik het + zeer op prijs stellen als deze mensen zich in kontakt met + onze glorieuze (ahum ahum) stichting stellen. + + + A A N R O E P + + De tweede methode wordt bv. aangeroepen wanneer de disk uit + de drive verwijderd wordt tijdens een BDOS aktie, maar ook + indien de 'Disk write protect' aktief is wanneer iets + gesaved wordt. De aanroep is op het eerste gezicht wat + ingewikkeld, het gaat nl. via een dubbele pointer aanroep. + + Bij een aanroep naar de foutafhandeling wordt eerst de 16 + bits adreswaarde vanaf adres &HF323 gelezen (de eerste + pointer). Daarna wordt het 16 bits adres gelezen van de + eerder gelezen adreswaarde. Daarna wordt de code uitgevoerd + vanaf het net gelezen adres. + + Oftewel bv.: + + (&HF323) = &H72AE + (&H72AE) = &H72B0 + &H72B0 = Start van fout afhandelingscode. + + Het lijkt misschien wat onlogisch, maar daarover moet u niet + bij mij zijn om over te klagen. + + + G E G E V E N S I N V O E R + + Bij de foutafhandelings code aangekomen staat in het C + register een waarde die de opgetreden fout omschrijft. De + bij mij (overigens niet met 100% zekerheid) bekende + foutcodes zijn: + + C >= 128 (bit 7 is hoog), dan "Bad FAT" + C AND &H0F = 1, dan "Disk write protected" + C AND &H0F < 4, dan "Disk offline" + C AND &H0F = 11, dan "Disk write error" + + Of er ook nog anderen zijn weet ik niet, maar dit zijn toch + wel de belangrijkste. Persoonlijk denk ik dat de lijst + langer moet zijn omdat de "Disk write error" mij iets te + algemeen is. Is deze fout gelijk aan een "Disk full" of gaat + het om een fysieke fout op het medium? Wat ik ook mis zijn + de foutmeldingen die via PHYDIO (CALL &H0144) verkregen + kunnen worden. + + + G E G E V E N S U I T V O E R + + Het is ook mogelijk om via het C register een waarde terug + te geven aan de BDOS. Persoonlijk ken ik er twee. Indien + voor de RET instruktie (om de foutafhandeling te verlaten) C + op 0 wordt gezet komt dat overeen met Abort. Indien C een + andere waarde heeft (bij voorkeur C=1) komt dat overeen met + Retry. + + Hier kleven echter nog wat haken en ogen aan. De Abort is + nl. de schrik voor elke ML programmeur omdat dan automatisch + naar BASIC teruggekeerd wordt! De Retry werkt wel naar + behoren en werkt als een (Sunrise) zonnetje. Het moet vast + wel mogelijk zijn om te voorkomen dat met de Abort naar + BASIC gesprongen wordt, maar het blijkt dat zelfs mensen met + de nodige documentatie niet weten hoe dat moet. Daarom heeft + iemand op een helder moment het volgende truukje bedacht, + wat misschien niet helemaal netjes is, maar nood breekt wet. + + + D E A B O R T A B O R T + + Wat we proberen is om de Abort mogelijkheid zelf te + programmeren (dus niet meer via de BDOS). Dat betekent dat + de BDOS aanroep vroegtijdig afgebroken moet worden. Om dat + te kunnen doen moet men in het uiterste geval drie dingen + weten, te weten: + - De stackpointer voor aanroep naar de BDOS + - De slot en subslot settings van page 1 voor aanroep + - De slot en subslot (turbo R) settings van page 0 + + Deze laatste is alleen nodig indien de BIOS op page 0 + vervangen is door bv. RAM geheugen. Om dit te verduidelijken + zal ik eerst maar even noemen wat de BDOS allemaal doet + indien deze aangeroepen wordt. + + Ten eerste wordt de BIOS op page 0 geschakeld. Daarna wordt + de BDOS op page 1 geschakeld. Dit laatste is de reden waarom + het FCB nooit op page 1 mag staan en waarom - volgens de MSX + standaard - niet op het adresgebied van page 1 geladen mag + worden alhoewel dit op de meeste MSX'en wel zal werken (met + uitzondering van de Sony's). De oude settings van page 1 + worden echter wel bewaard om ze na de uitvoer van de BDOS + actie te kunnen herstellen. Of de settings van page 0 ook + hersteld worden weet ik niet, maar ik heb mijn vermoedens + dat dit wel gebeurt (vanwege MSX-DOS). + + Aangenomen dat we in een eigen geschreven fout + afhandelingsroutine zitten (Door de eerder genoemde pointer + aanroep af te buigen). Willen we een Retry doen dan is dat + simpel. Maak register C maar 1 en geef een RET instruktie. + Simpeler kan niet. Om bij een Abort de BDOS aanroep + vroegtijdig af te breken moeten we de eerder genoemde + gegevens over de stackpointer en de page settings + herstellen. + + Page 0 moet alleen dan hersteld worden wanneer deze voor de + BDOS aanroep niet als BIOS geschakeld was (slot 0, subslot + 0). + + Er vanuit gaande dat page 0 als BIOS geschakeld is kan page + 1 als volgt hersteld worden. + + Was de BASIC-ROM geschakeld voor aanroep: + LD A,(&HFCC1) ; Slot & subslot van MAIN-ROM + CALL &H24 + LD SP,(SP_SAV) ; Voor BDOS aanroep bewaarde SP + LD A,1 ; Simuleer BDOS error + JP CONT ; Ga verder vanaf CONT: + + Was de MAIN-RAM geschakeld voor aanroep: + LD A,(&HF342) ; Slot & subslot van MAIN-RAM + CALL &H24 + etc. + + Door het A register van een andere waarde dan 0 te voorzien + kan een BDOS error code gesimuleerd worden. Het lijkt dan + nl. net alsof de BDOS een foutmelding via methode 1 terug + geeft. Het bewaren van de SP voor de BDOS aanroep is ook + heel simpel: + + LD (SP_SAV),SP + CALL &HF37D ; Roep BDOS aan + CONT: NOP ; Continue na Abort + + Kijk in dit verband ook eens naar de listing EASYBDOS.ASC + waar dezelfde methode in verwerkt is. + + + B R O E V A H A R O + + Oftewel "Hoera bravo", maar dat zag Obelix niet zo duidelijk + meer toen hij dronken door Lutetia liep. U zou nu voldoende + informatie moeten hebben om na enige zelfstudie eens wat te + gaan proberen. Mag ik daarbij nog wel de tip geven om altijd + met een klad diskette te werken, want de BDOS heeft de + oneigenaardige neiging om diskjes te vernielen wanneer er + aan de BDOS geknoeid is. Vergeet dus nooit om afgebogen + pointers of zelfs de BDOS aanroep hook te herstellen voordat + weer regulier van de BDOS gebruik gemaakt gaat worden! + + Van alle systeemonderdelen van MSX heeft de BDOS het voor + elkaar gekregen om haar geheimen het langst te bewaren. + Langzaam maar zeker zal ook de BDOS haar geheimen prijs + geven en dat is maar goed ook. Veel succes bij uw BDOS + projekten. + + Alex van der Wal + \ No newline at end of file diff --git a/sunrise_special/4/Boot2com.md b/sunrise_special/4/Boot2com.md new file mode 100644 index 0000000..857d5d3 --- /dev/null +++ b/sunrise_special/4/Boot2com.md @@ -0,0 +1,51 @@ + B O O T 2 C O M + + + Dit programma heb ik geschreven om spellen die w�l een + bootsector gebruiken om te laden, maar niet op sectorniveau + staan (daar is GETDISK al voor) toch op harddisk te kunnen + plaatsen. + + + W E R K I N G + + De syntax is: BOOT2COM + + Dit laadt de bootsector van (":" mag worden + weggelaten) in , waarbij .COM de standaard + extensie is. heb ik erbij gezet zodat het + mogelijk is om alle start-files in ��n directory te zetten + die in PATH zit. + + Bijv. BOOT2COM D: A:\BATCH\SSRV2.COM C:\GAMES\SSRV2 + + Als je dit programma hebt gerund, krijg je een file en moet + je de files van de diskette (bij mij D:) in de directory + zetten die je hebt opgegeven bij BOOT2COM (hier dus + C:\GAMES\SSRV2). + + Bij het voorbeeld dus: + + MD C:\GAMES\SSRV2 + COPY D:\*.* C:\GAMES\SSRV2 + + En hierna kun je, mits je A:\BATCH in je PATH hebt zitten, + door SSRV2 in te typen het spel opstarten. + + + T E S T V E R S I E + + Het is een testversie dus verwacht niet dat alle fouten bij + het aanmaken van een file worden opgevangen. + + + W E R K E N D E S P E L L E N + + Spellen die ermee werken hebben een boot-sector, maar + bestaan toch compleet uit files. In de boot-sector wordt dan + een file geladen. Tot nu toe werkt alleen Starship + Rendez-Vous disk B. Als je nog een spel hebt gevonden dat + ermee werkt, laat het dan s.v.p. weten via Sunrise BBS Nuth + of de postbus. + + Kasper Souren diff --git a/sunrise_special/4/Circle.md b/sunrise_special/4/Circle.md new file mode 100644 index 0000000..7c7f801 --- /dev/null +++ b/sunrise_special/4/Circle.md @@ -0,0 +1,206 @@ + C I R C L E + + + Met het CIRCLE commando in BASIC kunt u heel wat meer doen + dan simpele cirkeltjes tekenen. In dit artikel zal ik de + volledige syntax behandelen en twee eenvoudige listings + bespreken die gebruik maken van het CIRCLE commando. + + + S Y N T A X + + De volledige offici�le syntax van het CIRCLE commando luidt: + + CIRCLE [STEP] (x co�rdinaat middelpunt,y co�rdinaat middel- + punt), straal, [kleur], [beginhoek], [eindhoek], [hoogte/ + breedte verhouding] + + x en y co�rdinaten middelpunt tussen -32768 en +32767 + straal tussen -32768 en +32767 + kleur afhankelijk van SCREEN: 0-15 in SCREEN 2,3,4,5,7,10 + 0-3 in SCREEN 6 + 0-255 in SCREEN 8,11,12 + + Dit was al wel bekend neem ik aan. Voordat ik verder ga met + de beginhoek en eindhoek, moet ik eerst even uitleggen wat + radialen zijn. + + + R A D I A L E N + + Iedereen kent het getal pi wel, 3.1415926... Pi is precies + de omtrek van een cirkel met diameter 1. Stel je hebt een + molen waarvan de wieken precies 1 meter lang zijn, de + diameter van de wieken samen is dan dus 2 meter en de omtrek + van de cirkel die de wieken 'in de lucht tekenen' is gelijk + aan 2pi. Als een wiek een heel rondje draait, legt het + uiterste puntje dus een afstand van precies 2pi af. + + In plaats van dat je zegt dat hij 360 graden is gedraaid, + kun je ook spreken van een draaiing van 2pi radialen. 180 + graden komt overeen met pi, 90 graden met 1/2pi, 45 graden + met 1/4pi, etc. In het algemeen geldt de volgende formule: + + = * pi / 180 + + Bij wis- en natuurkunde worden hoeken meestal in radialen + uitgedrukt, en de meeste rekenmachines met goniometrische + functies (sin, cos, tan) kunnen behalve graden ook in + radialen werken. + + We hebben deze kennis nodig, omdat de beginhoek en de + eindhoek bij het CIRCLE commando in radialen moeten worden + opgegeven. Oh ja, iets wat je ook nog nodig hebt is dat de + stand van de kleine wijzer om 3 uur overeen komt met 0, om + 12 uur met 1/2 pi, om 9 uur met pi en om 6 uur met 1.5 pi. + + + B E G I N - E N E I N D H O E K + + Je hoeft met het CIRCLE commando niet per se een hele cirkel + te tekenen, ook een gedeelte is mogelijk. Hiervoor gebruiken + we de begin- en eindhoeken. Voor beiden kan een waarde + tussen 0 en 2pi worden ingevuld. + + Je kunt in BASIC pi overigens zeer eenvoudig met een voor + BASIC maximale nauwkeurigheid verkrijgen met + + PI=4*ATN(1) + + (de ArcTaNgens van 1 is immers gelijk aan 1/4 pi) + + We kunnen dus bijvoorbeeld alleen het stuk "van twaalf tot + drie uur" tekenen met: + + CIRCLE (100,100),50,,0,PI/2 + + + S T R A L E N + + Het CIRCLE commando kan echter nog meer! Door een minteken + voor de hoek te zetten, zal hij namelijk het uiteinde van de + cirkelboog verbinden met het middelpunt door een lijn (zo'n + lijn heet dan een straal). Zo kunnen we dus een soort pacman + met bek naar rechts tekenen met: + + CIRCLE (100,100),50,,-PI/4,-7*PI/4 + + En door voor begin- en eindhoek hetzelfde getal op te geven + krijgen we alleen nog maar de lijn! Dit gebruiken we voor + een eenvoudig programma om cirkeldiagrammen oftewel taart- + diagrammen te tekenen. + + + T A A R T D I A G R A M + + 100 ' TAART.BAS + 110 ' Taartdiagram met CIRCLE commando + 120 ' Door Stefan Boer + 130 ' Sunrise Special #4 + 140 ' (c) Stichting Sunrise 1993 + 150 ' + 160 KEYOFF:SCREEN0:WIDTH80:COLOR15,0,0 + 170 DIMX(29) + 180 PRINT"Taartdiagram":PRINT + 190 PRINT"Voer de gegevens in, 0 om af te sluiten:":PRINT + 200 INPUTX(N):IFX(N)<>0ANDN<29THENT=T+X(N):N=N+1:GOTO200 + 210 PI=4*ATN(1):H=-2*PI:N=N-1 + 220 SCREEN5 + 230 CIRCLE(128,106),100 + 240 FORI=0TON + 250 CIRCLE(128,106),100,,H,H + 260 H=H+X(I)*2*PI/T + 270 NEXT + 280 GOTO280 + + Een overzicht van de gebruikte variabelen: + + X(0)...X(29) de waardes bij 'part' 0 t/m 29 + N aantal parten + T totale waarde van parten + PI 3.1415926... + H hoek + I lusteller + + De werking is vrij eenvoudig. We beginnen bij een hoek van + -2pi en tellen vervolgens telkens + + 2PI + X(I) --- + T + + bij de hoek op, dat is namelijk precies de hoek van part I. + + + H O O G T E / B R E E D T E + + Normaal gesproken tekent de computer een cirkel waarvan de + hoogte en de breedte twee keer zoveel pixels tellen als de + straal. Zo'n cirkel is echter (zeker in SCREEN 6/7) + nauwelijks rond te noemen, en bovendien wil je soms juist + een ovaal hebben. Daarvoor is de laatste parameter, de + hoogte/breedte verhouding. Hiervoor kan een willekeurig + positief getal worden ingevuld. + + Als dit getal kleiner is dan 1, dan wordt de hoogte met deze + verhouding vermenigvuldigd. Is het groter dan 1, dan wordt + de breedte door de verhouding gedeeld. + + Bij 50 Hz kunt u de volgende waardes gebruiken om cirkels te + krijgen die mooi rond zijn: + + SCREEN hoogte/breedte verhouding + + 2,3,4 1.4 + 5,8,10,11,12 1.36 + 6,7 0.68 + + + C I R K E L I N R E C H T H O E K + + We kunnen de hoogte/breedte verhouding gebruiken om een + routine te programmeren die een cirkel tekent die precies in + een rechthoek past. Hierbij moet wel even goed worden + nagedacht, want je doet heel snel iets verkeerdom. Het + uiteindelijke resultaat is onderstaande listing. + + 100 ' CIRKEL.BAS + 110 ' Tekent cirkel precies in rechthoek + 120 ' Door Stefan Boer + 130 ' Sunrise Special #4 + 140 ' (c) Stichting Sunrise 1993 + 150 ' + 160 KEYOFF:SCREEN0:WIDTH80:COLOR15,0,0 + 170 PRINT"Cirkel in rechthoek":PRINT + 180 INPUT"X1 ";X1 + 190 INPUT"Y1 ";Y1 + 200 INPUT"X2 ";X2 + 210 INPUT"Y2 ";Y2 + 220 SCREEN5 + 230 LINE(X1,Y1)-(X2,Y2),8,B + 240 XS=ABS(X1-X2):YS=ABS(Y1-Y2) + 250 XC=(X1+X2)/2:YC=(Y1+Y2)/2 + 260 V=YS/XS:IFV<1THENR=ABS(XC-X1)ELSER=ABS(YC-Y1) + 270 CIRCLE(XC,YC),R,,,,V + 280 GOTO280 + + De gebruikte variabelen weer op een rij: + + X1,Y1 coordinaten van hoekpunt rechthoek + X2,Y2 coordinaten van andere hoekpunt + XS breedte van rechthoek + YS hoogte van rechthoek + XC,YC coordinaten van middelpunt + V hoogte/breedte verhouding + R straal + + + T E N S L O T T E + + Er kunnen met cirkels zeer mooie figuren op het scherm + worden getoverd, maar dat laat ik graag aan uw fantasie + over. De theorie kan nu in ieder geval het probleem niet + meer zijn. + + Stefan Boer + \ No newline at end of file diff --git a/sunrise_special/4/Copdisk.md b/sunrise_special/4/Copdisk.md new file mode 100644 index 0000000..99b7dd6 --- /dev/null +++ b/sunrise_special/4/Copdisk.md @@ -0,0 +1,27 @@ + C O P D I S K + + + COPDISK is een kleine harddisk utility dat is voortgekomen + uit GETDISK en PUTDISK. + + Met COPDISK kan een 720 kB diskette worden gekopieerd door + gebruik te maken van de harddisk. De diskette wordt namelijk + in ��n keer ingelezen en op de harddisk opgeslagen. + Vervolgens kan hij zo vaak als je maar wilt worden + gekopieerd op een andere diskette. Dit programma is vooral + handig voor mensen die minder dan 1 MB geheugen in hun + computer hebben en dus met andere kopieerprogramma's twee of + meer keer moeten wisselen. + + De plaats waar COPDISK de diskette tijdelijk opslaat wordt + bepaald door het environment item TEMP. Dit item wordt ook + door MSX-DOS 2 gebruikt voor tijdelijke bestanden. + + Zorg er dus voor dat met + + SET TEMP=drive:\path + + een harddiskpartitie wordt opgegeven waar minimaal 720 kB + vrij is. Standaard wordt met TEMP verwezen naar A:\. + + Michel Shuqair diff --git a/sunrise_special/4/DOS2 Batchfiles.md b/sunrise_special/4/DOS2 Batchfiles.md new file mode 100644 index 0000000..97fd462 --- /dev/null +++ b/sunrise_special/4/DOS2 Batchfiles.md @@ -0,0 +1,381 @@ + D O S 2 B A T C H F I L E S + + + Op Sunrise Special #2 heeft al eens een tekst over de + mogelijkheden van MSX-DOS 2.31 gestaan. Ook stond op SRS#2 + een tekst over pipelining en redirectioning. Ik zal in deze + tekst echter wat praktijkvoorbeelden ervan geven: de + batchfiles die op mijn HD staan. + + Eigenlijk is dit alleen interessant voor HD-gebruikers, want + batchfiles nemen toch minstens 1 kB in van een diskette, en + het kost weer extra laadtijd. Op een harddisk maakt de + diskruimte niet bar veel uit, en de laadtijd is vrij kort. + + + D R I E S O O R T E N + + Je kunt batchfiles opdelen in drie soorten. De eerste zorgt + ervoor dat een aantal commando's gecombineerd worden zodat + er minder hoeft te worden getikt. De tweede soort zorgt ook + voor minder typewerk, maar heeft als doel het opstarten van + een programma, en eventueel nog iets doen na het be�indigen + ervan. En de derde soort is gewoon diversen. + + Dit opdelen in soorten is eigenlijk flauwekul, omdat het + natuurlijk op heel veel manier kan, maar ik heb het gedaan + om toch een beetje een overzichtelijke tekst te kunnen + typen. + + + F O R M A A T + + Ik houd zelf het volgende aan: namen van files, directory's + of drives met hoofdletters en interne DOS commando's met + kleine letters. Maar in deze tekst type ik alles gewoon met + hoofdletters, dit voor de duidelijkheid. + + + E E R S T E S O O R T + + Ik zal gewoon een aantal batchfiles bespreken. Deze staan + ook op deze disk onder dezelfde naam. + + + D M O V E . B A T + + COPY %1 %2 + ECHO Y|DEL %1>NUL + + MOVE kan normaal alleen files op ��n disk verplaatsen, dus + van de ene dir naar de andere directory. MOVE verplaatst dan + ook alleen de directory-entry. Ik verplaats echter vaak + files van de ene drive naar de andere. Dat kost normaal 2 + regels typewerk. Met DMOVE wordt dit gereduceerd tot ��n + regel. + + %1 is de eerste parameter die achter de batchfile staat. %2 + de tweede, enz. %0 is trouwens de ECHTE eerste parameter. + Hier zal ik later ook nog iets mee doen. + + COPY %1 %2 zorgt dus gewoon dat er een file gekopieerd + wordt. ECHO Y|DEL %1>NUL betekent dit: + + ECHO Y| stuur het teken y naar de input van het commando + dat erachter staat (pipelining). + + DEL %1 als de vraag "Erase all files (Y/N)? " komt, zal + hier automatisch een Y worden gegeven. + + >NUL stuur de output van de voorgaande commando's naar + het NUL device. Dit houdt in dat er niks op het + schemr komt. + + + M O V D I R + + MD %2 + MOVE %1 %2 + RD %1 + + Deze batchfile gebruik ik om snel een directory in een + andere directory te plaatsen. Als je bijvoorbeeld eerst de + subdirectory TSRS in de rootdir hebt staan, en je wilt deze + verplaatsen naar de subdir MEMMAN, doe je het volgende: + + MOVDIR \TSRS \MEMMAN\TSRS + + Nu wordt eerst de directory TSRS aangemaakt in MEMMAN, dan + worden alle files gemoved van \TSRS naar \MEMMAN\TSRS en + tenslotte wordt de directory \TSRS verwijderd. + + Eventueel zou dit ook nog uitgebreid kunnen worden naar + DMOVDIR, die ik zelf echter niet op mijn HD heb staan, omdat + bij MOVE de FAT niet veranderd wordt, en bij COPY wel. En + een directory blijft meestal toch op dezelfde drive staan. + Maar voor de volledigheid... + + + D M O V D I R + + MD %2 + COPY %1 %2 + ECHO Y|DEL %1>NUL + RD %1 + + + D I V E R S E N + + Eigenlijk zou nu natuurlijk de tweede soort moeten komen. + Maar omdat die files gebruiken die moeten worden aangewezen + met het environment item PATH en er zijn nog een paar andere + environment items nodig. + + + A U T O E X E C . B A T + + BUFFERS 18 + + Zorgt ervoor dat het aantal buffers wordt vergroot. Dit + staat standaard op 5. In de buffers worden de FAT- en + directorysectoren bewaard, wat de laadtijd zeer ten goede + komt. + + IF NOT %TIME%A==24A A:\UTILS\ST4TUNE + + ST4TUNE.COM is een programma dat Star Trek quotes laat zien. + Er wordt telkens willekeurig ��n gekozen. Soms is het nodig + om AUTOEXEC.BAT nog eens op te starten, bijv. als de + environments items verneukt zijn. Als TIME dan nog goed + staat, wordt ST4TUNE niet gerund, omdat het toch ietwat + traag (CP/M) is. + + PATH H:\UTILS; A:\; A:\BATCH; A:\UTILS + PATH +A:\UTILS\TEXT; A:\UTILS\CRUNCH; A:\UTILS\ML + PATH +A:\UTILS\TURBOR; A:\UTILS\DOS2TOOLS; A:\BASIC + + Een aantal directory's in PATH zetten. BATCH moet uiteraard + VOOR UTILS staan, omdat sommige batchfiles gelijknamige COM + files gebruiken. Bijv. PMARC.BAT; zie verderop. Ook moet + eerst op de RAMdisk worden gezocht. + + ASSIGN F: G: + + Bij mij is E: de eerste echte diskdrive. Omdat ik maar ��n + diskdrive heb, is F: een virtuele drive. Dat betekent dat + ik, als ik naar F: vraag, de mededeling "Insert disk in + drive F: and strike a key when ready" krijgt. Dat vind ik + niet leuk, en daarom laat ik F: naar G: wijzen. Omdat G: + niet bestaat, bestaat F: nu ook niet meer voor lagere + systeemfuncties. + + Bij Disk I/O error wijst de computer overigens wel weer naar + de echte drive. Als je bijv. ASSIGN C: A: hebt gedaan, je + gaat naar C: en er is een Disk I/O error krijg je toch + "drive A:" op het scherm. + + Met ASSIGN zonder een drive (of letter) erachter wordt het + trouwens weer default gezet. + + SET TIME 24 + + Ik ben mijn horloge gewend, en heb liever niet am en pm + meldingen. + + SET DATE DD-MM-YY + + De Nederlandse manier van data. + + SET SHELL H:\UTILS + + COMMAND2.COM staat zo direct in H:\UTILS. + + SET PROMPT ON + + Prompt aan. Dus niet "A>", maar "A:\>". + + SET PATTERN C:\DIVERSEN\CHARSET + + Tja, PATTERN.COM is een programma dat nog niet is + vrijgegeven. Ik denk wel dat het op de volgende Special + staat. + + SET EXPERT ON + + Expert mode aan. COM files die van DOS1 disks worden + opgestart werken gewoon. + + SET TEMP H:\ + + Tijdelijke bestanden (o.a. bij pipelining gebruikt) in H:\. + + SET HELP C:\TEKST\HELP + SET KHELP %HELP% + + Japanse HELP (Kanji HELP) files hoef ik niet... Die zijn dus + hetzelfde als de Engels HELP files. + + IF NOT A%MEMMAN%==AON SET MEMMAN OFF + + Het environment MEMMAN wordt op OFF gezet als het niet aan + stond. MEMMAN wordt ON gezet door MEMMAN.BAT. + + RAMDISK 384 + + MD H:\UTILS + COPY A:\COMMAND2.COM H:\UTILS + COPY A:\UTILS\DOS2TOOLS\KEY.COM H:\UTILS + + RAMdisk aanmaken, en 2 files erop zetten. Ik wilde eerst + functietoetsen gebruiken onder DOS. Moet ik weer in orde + maken. + + ECHO N|PATTERN STANDARD>NUL + + Ik laad de standaard karakterset in, omdat ik anders gek + word van het yen-teken. + + KEY ON + + Functietoetsen aan en dan zit ik in DOS. + + + R E B O O T . B A T + + MODE 80 + TURBOSW 2 + COLOR 15,0,0 + + Scherm weer goed zetten, R800-DRAM aan. + + SET R1=%REBOOT% + SET REBOOT= + + Via het env. item REBOOT kan een commando worden meegegeven + dat wordt uitgevoerd als je terug naar DOS gaat. REBOOT + wordt in een ander item gekopieerd omdat je anders het + effect zou kunnen krijgen dat er de volgende keer weer + hetzelfde wordt gedaan als je terug naar DOS gaat. + + %R1% + + SET R1= + + Het env. item R1 wordt gewist als er nog wordt teruggekeerd + naar de batchfile of als R1 een intern DOS commando was. + + + T W E E D E S O O R T + + Nu worden batchfiles besproken die een ander programma + inladen. Om te beginnen een hele simpele. + + + P M A R C . B A T + + SET UPPER ON + PMARC.COM %1 %2 %3 %4 %5 %6 %7 %8 %9 + SET UPPER OFF + + Het item UPPER is ervoor om te zorgen dat alle kleine + letters die in parameters voorkomen in hoofdletters worden + omgezet. Dit is voor sommige CP/M programma's, die anders + niet goed functioneren. Hiertoe behoren PMARC en PMEXT. + + Omdat het voor sommige programma's ook mooi is om kleine + letters te kunnen gebruiken (waaronder INPUT.COM, zie + Sunrise Magazine #6), wordt UPPER ook weer op OFF gezet. + + + M E M M A N . B A T + + IF %MEMMAN%==ON ECHO + IF %MEMMAN%==ON ECHO *** MemMan already installed + IF %MEMMAN%==ON EXIT + + Als MemMan al eens is ingeladen, wordt teruggekeerd naar + MSX-DOS. Dit gebeurt met EXIT. Als je COMMAND2 intypt zonder + iets extra, kost dat geheugen, en bij EXIT wordt dit weer + vrijgegeven. Probeer voor de lol trouwens een COMMAND2>PRN. + Zorg wel dat de printer aan staat! Als je dan ECHO Tekst>CON + intypt, krijg je w�l weer iets op het scherm. Achter EXIT + kan ook nog een foutcode worden opgegeven. + + CLS + + PATH +A:\MEMMAN + SET MEMMAN=ON + SET REBOOT=%1 + SET TL=A:\MEMMAN\TSRS + + Het path wordt uitgebreid met A:\MEMMAN. De TSR directory + wordt goed gezet en de parameter die is meegegeven achter + MEMMAN.BAT wordt in REBOOT gezet. + + MEMMAN.COM + + + A F T E R M M . B A T + + Mijn MEMMAN.COM zet '_SYSTEM("AFTERMM.BAT")' in de + keyboardbuffer. AFTERMM betekent "after MemMan". + + CLS + ECHO Loading CHGCPU2.TSR and MBTSR.TSR... + + TL CHGCPU2>NUL + TL MBTSR>NUL + + Laad een paar TSR's in. + + REBOOT + + REBOOT opstarten. Het commando dat eerst achter MEMMAN.BAT + stond wordt dan via REBOOT.BAT uitgevoerd. Hier volgt een + batchfile die een MemMan programma uitvoert... + + + M P . B A T + + IF %MP%A==A SET MP=%1 + IF %MP%A==A SET MP=B:\MOD + + Als MP leeg is, wordt de parameter achet MP.BAT in MP gezet. + Als MP nu nog leeg is, en dus niks in de parameter zat, + wordt MP gevuld met de directory waar MOD files in staan. + + IF NOT %MEMMAN%A==ONA MEMMAN MP + + Als MemMan nog niet in het geheugen zat, wordt het nu + geladen. Bij terugkomst in DOS wordt MP.BAT weer uitgevoerd. + Vandaar ook dat %1 in een environment item wordt gezet. + + MP2.COM %MP% + + MP2.COM is een ietwat aangepaste versie van de MOD-player. + + SET MP= + + %MP% wordt weer gewist. + + + M C M . B A T + + Dit programma laadt MCM-Index in. + + PPDIR PUSH + + De huidige directory bewaren. + + CDD H:\ + + Overgaan op H:\. CDD wordt besproken op Sunrise Special #2. + + IF NOT EXIST MCM.COM COPY C:\DIVERSEN\MCMINDEX\MCM.COM + IF NOT EXIST MCM.DAT COPY C:\DIVERSEN\MCMINDEX\MCM.DAT + IF NOT EXIST MCM.SET COPY C:\DIVERSEN\MCMINDEX\MCM.SET + IF NOT EXIST TREF.NDX COPY C:\DIVERSEN\MCMINDEX\TREF.NDX + IF NOT EXIST SOORT.NDX COPY C:\DIVERSEN\MCMINDEX\SOORT.NDX + + Als bovenstaande files nog niet in H:\ staan, worden ze + gekopieerd van de directory C:\DIVERSEN\MCMINDEX. MCM Index + werkt namelijk een stukje sneller vanaf RAMdisk. + + KEY OFF + + Het programma kan niet tegen functietoetsen onder DOS. + + H:\MCM.COM + KEY ON + PPDIR POP + + Directory herstellen. + + + G E N O E G + + Ik hoop dat dit genoeg is om zelf handige batchfiles te + kunnen maken. Als er echter vragen zijn, schrijf dan naar de + postbus of het bel Sunrise BBS Nuth. + + Kasper Souren diff --git a/sunrise_special/4/De Programmeertaal C deel 5.md b/sunrise_special/4/De Programmeertaal C deel 5.md new file mode 100644 index 0000000..7a4adea --- /dev/null +++ b/sunrise_special/4/De Programmeertaal C deel 5.md @@ -0,0 +1,679 @@ + D E P R O G R A M M E E R T A A L C + + D E E L 5 + + + + N.B.: Dit is het vijfde deel van de serie. Bekendheid met de + eerste vier delen wordt verondersteld! + + + C O M P L E X E D A T A T Y P E N I N C + + + I N L E I D I N G + + De kracht van C zit hem in het feit dat er zowel 'dichtbij' + de machine geprogrammeerd kan worden (waardoor er veel + minder vaak naar assembler hoeft te worden gegrepen) als + heel abstract, iets wat PASCAL programmeurs vaak als hun + specifieke terrein beschouwen. + + In feite heeft PASCAL maar twee dingen voor op C: + enumeraties en sets. Enumeraties zijn gemakkelijk te + vervangen door constanten, sets geven wat meer problemen, + maar in C zijn wel uitgebreide bitmanipulaties mogelijk die + dit gemis kunnen opvangen - en een stuk efficienter. (In + ANSI C heeft men de taal overigens uitgebreid met + enumeraties, maar ANSI C is niet voor de MSX te krijgen.) + + Bij voorbaat wil ik de gebruikers van Small C waarschuwen + dat het meeste van wat in deze aflevering staat niet geldt + voor deze compiler: buiten het enkelvoudige array kent Small + C geen samengestelde datatypen, geen casts, geen + initializers en is het geheugenbeheer - mogelijk afhankelijk + van de verschillende versies - beperkt. + + + S A M E N G E S T E L D E T Y P E N + + Of we abstract kunnen programmeren hangt er vooral vanaf of + we onze gegevens astract kunnen maken. Blijven we steken op + het niveau van bits, bytes of words (machinetaal, maar ook + BASIC) dan maken we het onszelf heel moeilijk om + begrijpelijke en dus foutloze programma's te schrijven als + we wat meer gecompliceerde algorithmen willen gebruiken. + + + A R R A Y 'S , P O I N T E R S E N D E "C A S T " + + Array's en pointers zijn natuurlijk in deel drie al + behandeld, toch komen hier nog een paar dingen aan de orde + die niet eerder aan bod zijn gekomen. + + In de eerste plaats moet ook binnen declaraties rekening + worden gehouden met de prioriteit en volgorde van + "evaluatie" van de "operatoren". Ik gebruik hier + aanhalingstekens omdat er natuurlijk niet echt sprake is van + een rekenkundige uitdrukking, maar het lijkt er veel op. + + In declaraties komen gelukkig alleen de '()', de '[]' en de + '*' "operator" voor. De '()' en de '[]' hebben een hogere + prioriteit dan de '*'. (De '()'is de 'functie-return' + operator; deze valt echter buiten het bestek van deze + aflevering.) Gewone haakjes kunnen gebruikt worden als deze + prioriteit ons niet bevalt. De "evaluatie" verloopt voor de + '()' en '[]' van links naar rechts, die van de '*' precies + omgekeerd. Gelukkig hoeven we met dat laatste bij + declaraties geen rekening te houden, omdat het de enige + "operator" is met die prioriteit die in declaraties kan + worden gebruikt. + + Zo is na + + char *vb1[10]; + + 'vb1' een array van 10 pointers naar char, en na + + char (*vb2)[10]; + + 'vb2' een pointer naar een array van 10 chars, iets heel + anders. In het laatste geval hadden we ook kunnen schrijven: + + char (*vb2)[]; + + Er wordt namelijk geen array gedeclareerd (waarvoor geheugen + gereserveerd zou moeten worden), maar een pointer naar een + array. Binnen C hoef je in zo'n geval de grootte van het + array niet op te geven, wat logisch is: in C wordt toch niet + gecontroleerd of een array index binnen de grenzen valt! + + Het is in principe mogelijk de declaraties zo ingewikkeld te + maken als je zelf wilt, als je bovenstaande regels maar in + acht neemt. (In het bijzonder kun je dus een array maken met + twee of meer dimensies!) Het is echter bijzonder gemakkelijk + om hierin fouten te maken, of het overzicht te verliezen, + vooral omdat lang niet alle compilers meldingen geven als we + dingen (bijvoorbeeld pointers en int's) doorelkaar halen. + ASCII-C vormt hierop gelukkig een uitzondering. + + Maar stel dat we juist wel bepaalde datatypen doorelkaar + willen gebruiken? Dit komt vaker voor dan je op het eerste + gezicht denkt. Zo verwachten sommige standaardfuncties een + unsigned als een van hun parameters, maar vaak is de waarde + alleen als int beschikbaar. (Zie ook 3.1 voor een voorbeeld + hiervan.) Hoe gaan we dan te werk? + + Allereerst moet de de waarde van de int natuurlijk wel + positief zijn, want unsigned's zijn altijd positief. Is dat + het geval dan volstaat het voor de uitdrukking '(unsigned)' + te zetten. In meer algemene termen: zet een declaratie van + het gewenste type waarin een variabelenaam ontbreekt tussen + haakjes en voor de uitdrukking, en voila! We hebben van + datatype gewisseld. Deze operatie wordt een 'cast' genoemd. + + Een 'cast' kan alleen worden uitgevoerd bij enkelvoudige + datatypes (unsigned, int, char en pointers), wat logisch is, + want alleen deze mogen gebruikt worden bij een assignment + ('=' operator), of als functieparameter en -return. Ook de + 'cast' operator heeft een prioriteit, uiteraard, en die is + dezelfde is als die van '++', '--', enz. + + Overigens wordt bij een assignment meestal een automatische + cast uitgevoerd naar het gewenste type, bijvoorbeeld: + + int g1; + char g2; + + g1 = 65; + + g2 = g1; + + Hierna bevat g2 een 'A', als het systeem waarop we werken + tenminste de ASCII-code gebruikt. Waar echter nooit + automatische casts worden uitgevoerd zijn functie-parameters + en -returns, wat bij ASCII-C tot problemen kan leiden, omdat + char's aan de ene kant, en unsigned's, int's en pointers aan + de andere kant op verschillende manieren worden door- en + teruggegeven. De functie parameter checker van ASCII-C + (FPC.COM) ontdekt dit soort fouten wel, maar het is niet + verplicht deze te gebruiken! + + Bij HiSoft C moet een cast op een iets andere manier gegeven + worden: voor de haakjes moet nog het woord 'cast' worden + gebruikt. Het al eerder gebruikte voorbeeld zou dan: + 'cast(unsigned)' worden. Naar eigen zeggen is dit gedaan om + de compiler simpeler te houden, maar het komt niet overeen + met enige standaard. + + + + S T R U C T S + + Structs gebruiken we als we verschillende gegevens bij + elkaar willen opslaan. Als voorbeeld nemen we een punt in de + ruimte: deze heeft een X, Y en Z coordinaat. Gesteld dat we + genoegen nemen met int's voor deze coordinaten dan hebben we + na + + struct point { int x,y,z; } pnt1; + + een variabele 'pnt1' gecreeerd die uit drie int's bestaat + met de namen 'x', 'y' en 'z'. Deze struktuur (vandaar + 'struct') is nu bekend onder de naam 'point', zodat we met + bijvoorbeeld + + struct point pnt2; + + de variabele 'pnt2' in het leven roepen, die op precies + dezelfde manier is samengesteld. We zijn overigens niet + verplicht een struct een naam (we spreken in C ook wel over + 'tag name') te geven, maar het is vaak heel handig. + Omgekeerd kun je ook de naam van de variabele weglaten. Er + wordt dan uiteraard geen variabele gecreeerd, maar de struct + is dan wel gedefinieerd. Dit gebeurt nogal eens in + '#include' files waarin we dit soort definities voor een + aantal modules tegelijk willen vastleggen. + + Om toegang te krijgen tot het "inwendige" van een struct - + de 'members' (= leden) - gebruiken we de '.' operator + gevolgd door de naam van het lid. Als we de Z-coordinaat + willen bereiken van 'pnt1' is + + pnt1.z + + voldoende, en dit samenstel is als gewone variabele te + gebruiken. Veel algorithmen maken gebruik van lijsten of + boomstrukturen. Hiervoor is nodig dat er in de de struct een + of meer pointers zitten naar andere variabelen van hetzelfde + type. Als voorbeeld kunnen we denken aan een lijst woorden, + of namen. De pointer in de struct wijst dan naar de struct + met de volgende naam, en de pointer daarin naar de + daaropvolgende, enzovoort. (In de laatste struct maken we de + pointer NULL.) + + struct name { struct name *next; + char print_name[20]; } firstname; + + Dit geeft aan hoe we zoiets kunnen doen. Nu we het toch over + pointers hebben: er bestaat een verkorte schrijfwijze om een + member van een struct te bereiken uitgaande van een pointer + naar een struct. Hou bovenstaande struct in gedachten, en + bekijk het stukje C hieronder: + + struct name *pointer; + + pointer = &firstname; + + pointer = pointer->next; + + Het gaat hier natuurlijk om de '->'. Volledig identiek met + de laatste regel zou zijn: + + pointer = (*pointer).next; + + (De haakjes zijn nodig omdat de '.' operator een hogere + prioriteit heeft dan de '*' operator.) Het behoeft geen + betoog dat de andere schrijfwijze korter is, en zeker zo + duidelijk. + + Als een struct eenmaal 'bekend' is, of beter gezegd: + gedefinieerd is, kan een struct precies zo gebruikt worden + als een gewone variabele, al zijn er een paar restricties. + Zo kan een struct niet als parameter van een functie worden + gebruikt, maar een pointer naar een struct mag wel, en dat + voldoet in bijna alle gevallen even goed. + + Een vervelender restrictie is het feit dat de '=' operator + niet gebruikt mag worden op structs: we moeten de leden stuk + voor stuk kopieren, of gebruik maken van de 'movmem'- of + 'memcpy'-functie. (Deze functies worden verderop in deze + tekst besproken.) + + Wat wel weer mag is in de definitie van een struct een + andere struct gebruiken. Een uitgebreid voorbeeld hiervan + staat aan het eind van het volgende gedeelte. + + + + U N I O N S + + Unions lijken een beetje op structs. De manier waarop ze + gedefinieerd en gebruikt worden is zelfs precies gelijk aan + structs, als je het woord 'union' voor 'struct' invult. Het + grote verschil is dat in een struct alle leden tegelijk + bruikbaar zijn, en in een union slechts een lid tegelijk. Of + om het anders te zeggen: in een union zijn de leden 'bovenop + elkaar' gelegd, en in een struct 'naast elkaar'. + + Een voorbeeldje maakt alles misschien duidelijker: + + union char_int { char letter; + int getal; } uvar; + + We kunnen nu bijvoorbeeld doen: + + uvar.letter = 'A'; + + Nu bevat uvar.letter het karakter 'A', en is uvar.getal niet + gedefinieerd. Na + + uvar.getal = 123; + + bevat uvar.getal de waarde 123, en is de waarde van + uvar.letter niet gedefinieerd. + + Hadden we een struct gebruikt, in plaats van een union, dan + had uvar.letter nu nog steeds de waarde 'A', maar een struct + gebruikt daarom wel meer geheugen: een struct gebruikt + evenveel geheugen als de som van het geheugengebruik van de + afzonderlijke leden, een union gebruikt slechts zoveel + geheugen als het grootste lid. + + Bovenstaand voorbeeld zal wel het gebruik, maar zeker niet + de zin van de union duidelijk maken. Als leden van een union + worden dan ook meestal zelf ook samengestelde typen + (array's, structs, unions) gebruikt, al dan niet samen met + simpeler typen. Als voorbeeld een door mijzelf in een + programma gedefinieerde struct: + + struct node { char nodetype; + union { + struct { struct node *left, *right; } ptr_node; + CONSTANT con_node; + VARIABLE var_node; } nodeinfo ; }; + + CONSTANT en VARIABLE zijn met een 'typedef' (zie 2.4) + gedefinieerde types. Binnenin de struct 'node ' worden op + hun beurt een struct en een union gedefinieerd. Om de + variabele 'left' te bereiken is na de naam van de + struct-variabele nodig: '.nodeinfo.ptrnode.left', waarbij + 'nodeinfo' de naam is van de union, het tweede lid van van + de struct 'node', 'ptrnode' de naam wan het eerste lid van + de union, en zelf een struct, en 'left' de naam van het + eerste lid van de binnenste struct. Het is even wennen. + + Overigens, omdat ik juist 'left' en 'right' heel vaak moest + gebruiken, heb ik de volgende twee #defines gemaakt: + + #define NLEFT nodeinfo.ptrnode.left + #define NRIGHT nodeinfo.ptrnode.right + + Dat voorkomt kramp in de typevingers. + + + N I E U W E T Y P E N D E F I N I E R E N + + In het geval van structs en unions kunnen we een eenmaal + gedefinieerd type telkens opnieuw gebruiken, als we er maar + voor zorgen dat we het een 'tag name' hebben gegeven. Bij + arrays of ingewikkelde pointer types, of erger nog: + combinaties ervan, zou het handig zijn (en fouten voorkomen) + als we het type slechts een keer moesten definieren. Dat kan + met een zogenaamde 'typedef'. + + Het gebruik van 'typedef' is heel eenvoudig. Als je uitgaat + van de declaratie van de variabele van het gewenste type, + volstaat het om er het woordje 'typedef' voor te zetten, en + de naam van de variabele te vervangen door de naam die je + het nieuwe type wilt geven. + + Als je bijvoorbeeld een type LONG wilt maken (omdat je + compiler - zucht - geen long's kent) kun je bijvoorbeeld als + volgt te werk gaan: + + typedef char LONG[4]; + + Een LONG is dan gedefinieerd als een array van 4 char's, en + kan nu in declaraties worden gebruikt, zoals: + + LONG lang_getal1, lang_getal2; + + Natuurlijk heft dat geen van de beperkingen op die voor het + specifieke datatype gelden en dus zal bijvoorbeeld + + lang_getal1 = lang_getal2; + + tot een foutmelding leiden, zoiets als "must be lvalue", + omdat we hier in feite arraynamen, en dus pointerconstanten, + gebruiken! (Dat heeft weer wel als voordeel dat we bij ons + nieuwe type deze arraynaam zonder meer als parameter aan + functies kunnen doorgeven, zonder dat we specifiek het adres + hadden moeten doorgeven; alles heeft voor- en nadelen.) + + - Het volgende tekstdeel kunt u in het submenu vinden - + + + + - Het eerste tekstdeel kunt u in het submenu vinden - + + D E P R O G R A M M E E R T A A L C + + D E E L 5 + + + + G E H E U G E N B E H E E R I N C + + PASCAL programmeurs zullen zich bij al die pointers wel even + het hoofd hebben geschud. Immers, de enige manier waarop zij + met pointers kunnen werken is na een NEW, die een nieuwe, + anonieme variabele cre�ert, en een pointer ernaar + teruggeeft. Dat is (officieel) de enige manier waarop je in + PASCAL aan een pointer kunt komen. + + Deze beperkingen zijn waarschijnlijk opzettelijk, omdat + pointers tevens een belangrijke bron van fouten zijn. Zelfs + binnen het keurslijf van PASCAL kunnen pointers naar + niet-meer-bestaande objecten overblijven na een MARK/RELEASE + of DISPOSE. + + Toch is de keuze die men voor PASCAL gemaakt heeft zo gek + nog niet: bij anonieme variabelen moet je immers wel met + pointers werken, omdat je er niet bij naam naar kan + verwijzen, en bij veel algorithmen die gebruik maken van + bomen ('trees') en lijsten ('linked lists') - en dus + pointers - moet je nieuwe objecten kunnen cre�ren en oude + vernietigen. Vandaar dat men die link (woordspeling + opzettelijk!) tussen geheugenbeheer en pointergebruik legde. + + Inderdaad, geheugenbeheer. Voor wie het nog niet door had: + als je een nieuwe variablele wilt cre�ren dan heb je + (ongebruikt) geheugen nodig, en dat geheugen moet ergens + vandaan komen. In C zijn daar verschillende manieren voor, + de meest gebruikelijke zijn echter: + + calloc(aantal, grootte) + malloc(grootte) + alloc(grootte) + + De functie 'calloc' reserveert geheugen voor 'aantal' + objecten van 'grootte' bytes, 'malloc' en 'alloc' een blok + van 'grootte' bytes. Deze twee laatste doen dus precies + hetzelfde, tenminste op byte-georienteerde systemen zoals de + Z80. Alle parameters van alledrie de functies zijn unsigned, + en alledrie geven ze een char * terug naar het eerste byte + in het blok geheugen, of NULL als er onvoldoende geheugen + beschikbaar is. + + In tegenstelling tot PASCAL kunnen we dus niet direct een + bepaald object cre�ren, we zijn er zelf verantwoordelijk + voor om de juiste hoeveelheid geheugen te reserveren. + Gelukkig is dat niet zo moeilijk. Willen we bijvoorbeeld een + nieuw object van het type 'struct name' (zie eerder) dan kan + dat met + + malloc(sizeof(struct name)) + + en bij wat strengere compilers moeten we bovendien casts + gebruiken, en dan wordt het bovenstaande: + + (struct name *)malloc((unsigned)sizeof(struct name)) + + Dat ziet er lelijk - en onbegrijpelijk - uit. Zo'n + wanproduct kunnen we binnen een aparte functie plaatsen (wat + we kunnen combineren met een actie wanneer er onvoldoende + geheugen beschikbaar is) zoals: + + struct name *newname() + { + char *temp; + + if ((temp = malloc((unsigned)sizeof(struct name))) == + NULL) { fputs("Onvoldoende geheugen!\n", stderr); + exit(1); } /* einde programma! */ + + return (struct name *)temp; + } + + Als onze preprocessor voldoende krachtig is, en ook + #define's met parameters accepteert (zoals ASCII-C) kunnen + we ook het volgende doen: + + #define NEW(x) (((x) *)malloc((unsigned)sizeof(x))) + + en dan reserveren we altijd de juiste hoeveelheid geheugen + en krijgen we altijd het juiste type pointer terug, wat voor + data-type we ook voor x invullen. Nu kunnen we eenvoudig "a + la PASCAL" + + NEW(struct name) + + doen. Et voila! Deze manier is heel efficient, vooral omdat + het ons geen byte aan code extra kost: al die casts zijn er + tenslotte voor de interne administratie van de compiler. + + Omdat 'calloc(aantal, grootte') precies hetzelfde doet als + 'malloc(aantal * grootte)' zal 'calloc' hier wel geen + verdere toelichting behoeven. Waar in de rest van het + verhaal 'malloc' staat kan dus ook - mutatis mutandis - + 'calloc' of 'alloc' worden gelezen. + + Het geheugen dat we met een van bovenstaande functies hebben + gekregen kunnen we ook aan het systeem teruggeven, waarna + het weer voor beschikbaar wordt voor een volgende 'malloc', + 'alloc' of 'calloc'. Hiervoor is de functie + + free(pointer) + + beschikbaar. De parameter 'pointer' is een char * en we + moeten hier dezelfde pointer gebruiken die we via 'malloc' + e.d. hebben gekregen. De functie 'free' geeft geen waarde + terug. + + Meer voor de volledigheid dan om praktische redenen wil ik + hier nog vermelden dat C nog een functie heeft om geheugen + te reserveren, namelijk 'sbrk'. Niet alle C-compilers + ondersteunen deze functie, en bovendien kan met deze functie + gereserveerd geheugen niet terug worden gegeven aan het + systeem. Wederom een Unix-relikwie. + + Ook kent C nog een paar, weinig gebruikte functies om + blokken geheugen te verplaatsen of te vullen. Deze zijn: + + memcpy(dst, src, len) + movmem(src, dst, len) + memset(dst, byte, len) + setmem(dst, len, byte) + + De functies 'memcpy' en 'movmem' verplaatsen een blok + geheugen dat 'len' bytes groot is van 'src' naar 'dst' + ('len' is unsigned, 'dst' en 'src' zijn char *). Deze + functies zijn identiek, op de volgorde van de argumenten na. + Overigens mogen de 'src' en 'dst' gebieden niet overlappen. + De functies 'memset' en 'setmem' vullen een geheugengebied + vanaf 'dst', dat 'len' bytes groot, is met de waarde 'byte', + een char. Ook bij deze twee functies is alleen de volgorde + van de argumenten verschillend. Aangezien het ANSI comite + aan de functies 'memcpy' en 'memset' de voorkeur geeft is + het misschien verstandig dit zelf ook te doen. + + + S T R A T E G I E E N V A N G E H E U G E N - + + B E H E E R : E E N V E R G E L I J K I N G + + Vooral assemblyprogrammeurs zullen bij bovenstaand verhaal + de oren hebben gespitst en denken: "maar zijn er dan geen + restricties in de volgorde waarin geheugen wordt aangevraagd + en teruggegeven, en moet bij 'free' niet de grootte van het + blok geheugenblok worden vermeld?" Op beide vragen luidt het + antwoord: nee! Het geheugenbeheersysteem van C is erg + flexibel wat dat betreft, maar voor alles moet een prijs + worden betaald. + + In de eerste plaats moet het systeem zelf bijhouden hoeveel + geheugen er in een blok zit. De meestgebruikte manier omdat + te doen is de grootte van een blok direct voor dat blok op + te slaan, wat op zich al wat geheugen kost. + + In de tweede plaats moet een blok een bepaalde minimale + grootte hebben, of soms zelfs een veelvoud van een bepaalde + waarde, omdat er zelfs in een ongebruikt geheugenblok nog + bepaalde informatie moet worden opgeslagen. Deze twee feiten + maken het onaantrekkelijk om zeer veel kleine blokken te + gebruiken, omdat anders het verlies erg groot wordt. In zo'n + geval kan het aantrekkelijk zijn een of meer grote blokken + geheugen aan te vragen, en daar zelf een beheerstrategie + voor uit te denken. Vooral als we met stukjes geheugen van + allemaal gelijk formaat willen werken kan dit vaak heel + eenvoudig. + + Als laatste probleem wil ik noemen het (mogelijk) + versnipperen van het geheugen in allemaal kleine blokken, + wat tot gevolg kan hebben dat er geen blokken geheugen van + een bepaalde minimale grootte meer beschikbaar zijn, hoewel + de totale hoeveelheid vrij geheugen ruim voldoende kan zijn. + Een en ander hangt af van in welke volgorde we de blokken + aanvragen en weer vrijmaken, en hoe het formaat van de + verschillende blokken uiteenloopt. In de praktijk valt het + echter allemaal wel mee. + + Als vergelijking wil ik hier noemen de manier waarop BASIC + met strings omgaat. Strings in BASIC zijn variabel van + lengte, en voor een string kan dus geen vaste hoeveelheid + geheugen worden gereserveerd. Maar de geheugenallocatie voor + strings wordt veel simpeler aangepakt, en geheugen wordt ook + niet expliciet weer vrijgegeven. Als gevolg daarvan is het + geheugen dan ook vrij snel vol, en vervolgens gaat de + interpreter een zogenaamde 'garbage collection' uitvoeren, + die uiteindelijk tot gevolg heeft dat alle bezette delen + achterelkaar worden geplaatst, en er een enkel vrij blok + geheugen ontstaat. + + Dit klinkt op het eerste gezicht aantrekkelijk, maar er zijn + een paar problemen. Het belangrijkste is wel dat de + informatie verschuift, en alle pointers naar die informatie + aangepast moeten worden. In BASIC gaat dat nog wel, omdat de + interpreter het beheer over die pointers (lees: string + descriptors) voert, en precies weet waar ze zich bevinden. + In C is dit niet mogelijk, omdat de pointers (en mogelijke + kopieen daarvan) over het gehele geheugen verspreid kunnen + zijn, vaak in de geheugenblokken zelf! + + Dat zo'n garbage collection ook nog eens bijzonder traag + gaat is de BASIC programmeur wel bekend, hoewel dat laatste + voor een niet onbelangrijk deel aan de 'gierigheid' van de + BASIC-interpreter ligt: als ze twee bytes extra per string + hadden geinvesteerd hadden ze de garbage collection een orde + sneller kunnen maken, en hadden bovendien niet alle string + descriptors in hetzelfde geheugendeel hoeven liggen. Ik + spreek hier uit ervaring, want ik heb zelf eens een + stringuitbreiding voor FORTH geprogrammeerd, en ik heb het + systeem nooit zichtbaar zien vertragen tijdens een garbage + collection. + + Maar het feit dat de informatie in zo'n systeem van plaats + kan veranderen kan in veel gevallen toch tot problemen + leiden, en vraagt de nodige discipline van de gebruiker. In + bovenstaand FORTH systeem worden strings dan ook in een keer + naar de stack gekopieerd voor ermee gewerkt mag worden, en + ook weer in een keer weggeschreven, en dat maakt een en + ander toch weer wat minder efficient. (Al past deze + werkwijze wel bij uitstek in de FORTH-filosofie!) + + Binnen TURBO PASCAL kan op ongeveer dezelfde manier worden + gewerkt als in C met NEW/DISPOSE of GETMEM/FREEMEM, al moet + bij FREEMEM in tegenstelling tot C wel de grootte van het + geheugenblok worden opgegeven. Binnen TURBO PASCAL kan + echter ook met MARK/RELEASE worden gewerkt (maar dan niet + met DISPOSE of FREEMEM!) om alle blokken die aangevraagd + zijn na een bepaald eerder blok weer vrij te geven. Een en + ander functioneert dan ongeveer als een stack. C + programmeurs die hetzelfde willen kunnen doen moeten daar + zelf een routine voor schrijven, die echter bijzonder simpel + is als we in een enkel, aaneengesloten blok geheugen werken. + + + + I N I T I A L I Z E R S + + Een van de meestgebruikte statements in BASIC is 'DATA'. Er + zijn nauwelijks programma's van enige omvang die niet zijn + gezegend(?!) met een grote hoeveelheid van deze dingen, + meestal aan het eind. Zelfs als we die DATA's niet + meerekenen die gebruikt zijn om een stukje machinetaal in te + zetten - omdat het programma anders niet vooruit te branden + is - blijkt dat we er nog een hoop overhouden met tabellen + en dergelijke. + + Handige programmeurs maken vaak gebruik van tabellen, omdat + het programma er vaak een stuk simpeler en kleiner van + wordt. Ook op dit gebied laat C niemand in de steek, omdat + we al onze variabelen mogen intialiseren met een waarde of + waarden bij de declaratie ervan. Dit kan met een simpele + variabele als volgt: + + int var1 = 0; + char var2 = 'N'; + unsigned var3 = 5 * 4; + char *var4 = "En dit is ook een constante!"; + + We mogen variabelen alleen initialiseren met constanten, of + constante uitdrukkingen. Samengestelde typen mogen echter + alleen initialiseren als het statische variabelen zijn + (buiten een functie is dat altijd zo). Voor automatische + variabelen (die komen alleen binnen een functie voor) gelden + dezelfde beperkingen als die voor een assignment. (In feite + wordt het ook naar een assignment vertaald, wat logisch is: + bij het aanroepen van de functie moet de initialisa- + tie telkens opnieuw plaatsvinden!) + + In het het laatste voorbeeld van bovenstaand rijtje moeten + we ons realiseren dat we een pointer variabele initialiseren + zodat hij naar die string wijst; de string zelf zit op een + andere plaats in het geheugen. Doen we echter dit: + + char var4[] = "En nu vullen we een array!"; + + Dan wordt var4 een array, en gevuld met boventaande string. + Deze methode is wat efficienter want we sparen een pointer + variabele uit. We hoeven ook niet op te geven hoe groot het + array moet worden, want dat is gewoon de lengte van de + string met afsluitende nul: dat zoekt de compiler zelf wel + uit. + + Een string kan dus twee betekenissen hebben in een + initializer. De tweede manier gebruikt de string als een + blok gegevens, maar dit kan ook door een aantal constanten, + of constante uitdrukkingen, gescheiden door komma's, tussen + accoladen te zetten. De volgende twee declaraties zijn dan + ook volledig identiek: + + char str[] = "String"; + char str[] = { 'S', 't', 'r', 'i', 'n', 'g', 0 }; + + In het algemeen is de eerste vorm wat duidelijker, maar die + kunnen we natuurlijk alleen gebruiken als het om strings + gaat. In alle andere gevallen en bij alle samengestelde + typen moeten we van dit soort gegevensblokken tussen + accoladen gebruiken. In het geval we samengestelde typen + binnen samengestelde typen gebruiken moeten we zelfs + gegevensblokken binnen gegegevensblokken gebruiken. We + moeten zo'n blok dus eigenlijk zien als een samengestelde + constante. Hier een aantal voorbeelden: + + int rij[] = { 1, 2, 3 }; + int matrix[][] = { { 1, 2, 3 }, { 4, 5, 6 }, + { 7, 8, 9 } }; + struct point pnt3 = { 0, 1, -1 }; + struct point vlak[] = { { 1, 0, 0 }, { 0, 1, 0 }, + { 0, 0, 1} }; + char *teksten[] = { "tekst1", "tekst2", "tekst3", + "tekst4" }; + + + In het laatste geval hebben we een array van char pointers + gemaakt, en elk van die pointers wijst naar een van de + teksten. Verder nog vragen? Geen vragen! En dus wordt dit + het einde van deze aflevering! + + Robert Amesz + + + P.S.: Het zal misschien een aantal mensen opgevallen zijn + dat een voorbeeldprogramma deze aflevering ontbreekt. Sorry. + Dat komt pas bij aflevering 6, wanneer het over zulke + diverse onderwerpen zal gaan als modulair programmeren, het + maken van functiebibliotheken, debuggen, combineren met + machinetaal, enz. enz. diff --git a/sunrise_special/4/Dirsort.md b/sunrise_special/4/Dirsort.md new file mode 100644 index 0000000..c702c3e --- /dev/null +++ b/sunrise_special/4/Dirsort.md @@ -0,0 +1,192 @@ + D I R S O R T 1 . 0 + + + Met Dirsort is het mogelijk om al uw (sub)directory's bij te + werken, en de bestanden in de (sub)directory's op uw eigen + gewenste volgorde te plaatsen. + + + S Y S T E E M E I S E N + + Dirsort werkt op iedere MSX2 (of hoger) met MSX-DOS 2 en + minimaal 16 kB aan vrij RAM geheugen. + + + O P S T A R T E N + + Dirsort kan opgestart worden door achter de DOS-prompt + DIRSORT[+return] in te tikken, eventueel gevolgd door de + naam van een subdirectory, deze wordt dan meteen ingeladen. + + S C H E R M O V E R Z I C H T + + Het scherm is in twee kolommen ingedeeld, in de linkerkolom + staan de subdirectory's en in de rechterkolom de bestanden + die zich in deze subdirectory's bevinden met daarbij hun + lengte, aanmaak tijd en datum en de attributen. + + Bovenaan het scherm staan de drie menu's; Program, + Information en Options en daarnaast staan het Entry-nummer + van het bestand waar de cursor op staat. + + Onderaan het scherm wordt de huidige drive en pathnaam + getoond. + + + S E L E C T E R E N D I R E C T O R Y + + Als eerste moet de juiste drive gekozen worden, dit kan door + middel van het 'Program'-menu. Dit menu wordt opgeroepen + door op 'P' of 'F1' te drukken, het menu verschijnt dan en + de cursor staat al op de keuze 'Drives'. Door op Return of + de spatiebalk te drukken verschijnt er een tweede menu, + hierin staan alle aanwezige drives. Door de cursor nu op de + juiste drive te plaatsen en op return of op de spatiebalk te + drukken wordt deze drive de huidige drive. + + Dan wordt de huidige (sub)directory getoond, om nu de juiste + directory te selecteren bestaan twee mogelijkheden; de + eerste is via het menu 'Options-Change directory'. Er + verschijnt een blok met daarin de tekst Change Directory en + een lege regel, op deze regel moet dan de directory getypt + worden en deze zal dan worden ingelezen. + + De tweede manier is om de directory te kiezen via de + directory-namen die in de linkerkolom staat, dit gaat door + de cursor op ��n van deze namen te plaatsen en dan op de + spatiebalk te drukken. Deze directory wordt dan de huidige + directory. + + Als de juiste directory gekozen is dan kan er met schuiven + en sorteren begonnen worden + + + O P J U I S T E P L E K Z E T T E N + + De bestanden kunnen verschoven worden door ze eerst te + selecteren, dit gebeurt door de cursor op het bestand te + plaatsen en dan op de spatiebalk te drukken. Er verschijnt + nu 2 pijltjes ('>' en '<'), dit betekent dat het bestand + geselecteerd is. + + Deze bestanden kunnen verschoven worden door de de cursor op + de bovenste of de onderste positie te plaatsen en als dan + het lijst begint te verschuiven dan zullen de geselecteerde + bestanden meeschuiven. + + Ook kan er in 1 keer een hele pagina verschoven worden, dit + kan door middel van CTRL + de cursortoets omhoog of omlaag. + + + L I J S T S O R T E R E N + + De lijst kan gesorteerd worden door de optie 'Options-Sort + directory'. Dan kan er eerste gekozen worden op de lijst op + naam, extensie, lengte of datum en tijd gesorteerd moet + worden, dan of de subdirectory's vooraan moeten staan, de + files of alles doorelkaar. En als laatste of de bestanden + van A tot Z (sort up) gesorteerd moeten worden of van Z tot + A (sort down). + + Mocht het voorkomen dat een extensie, lengte of datum en + tijd gelijk zijn dan wordt daarna ook nog de bestandsnaam + vergeleken. + + + M E N U F U N C T I E S I N H E T K O R T + + Menu 1 (Program): + + - Drives (CTRL-D): met de functie kan de huidige drive + veranderd worden. + - Cursorspeed: met de functie kan de snelheid waarmee de + cursor beweegt verandert worden, dit in geval van uw + MSX-computer is uitgerust met 7 Mhz. + - Quit (CTRL-Q): hiermee kan het programma verlaten worden, + er wordt wel om een bevestiging gevraagd. + + Menu 2 (Information): + + - Memory information: er verschijnt een blok met daarin de + geheugengrootte, maximaal aantal entry's waaruit een + directory mag bestaan en het huidige aantal entry's. + - Disk informaties: er verschijnt een blok met daarin + informatie over de disk in de huidige drive, bijvoorbeeld + Volume naam, Volume ID, sectorgrootte, aantal sectors per + cluster, enz. + + Menu 3 (Options) + + - Change directory (CTRL-D): met deze funktie kan de er van + directory gewisseld worden door de naam er van in te + typen. + - Remove killed entry's (CTRL-R): met deze funktie worden + alle gewiste bestanden uit de lijst verwijdert, deze + kunnen dan niet meer via UNDEL.COM worden teruggehaald. + - Remove Tags (CTRL-T), alle bestanden die geselecteerd zijn + worden weer vrij gegeven. + - Sort directory (CTRL-S), de directory wordt op naam, + extensie, lengte of datum en tijd gesorteerd. + - Save directory, met de optie wordt de aangepaste directory + weggeschreven naar de disk, als de functie niet gebruikt + wordt zal de directory op de disk niet zijn veranderd. + + + M O G E L I J K E F O U T M E L D I N G E N + + "Out of Memory", er is te weinig geheugen beschikbaar om de + hele directory in te lezen. Er kan per 16 kB 512 entry's + ingelezen worden, het zal dus vaak niet nodig zijn om veel + geheugen vrij te hebben maar het is wel handig om zo'n 32 kB + vrij te hebben. Er kan dan al met grote subdirectory's (van + maximaal 1024 entry's) gewerkt worden. + + "No directory in memory", er is (nog) geen directory + ingelezen. Dit kan doordat er bijvoorbeeld te weinig + geheugen is (zie vorige foutmelding). + + "Another disk in drive", er wordt geprobeerd om de directory + te bewaren op een andere disk. De disk worden vergeleken op + volume-ID en eventueel op FAT in geval dat het om een + MSX-DOS 1 disk gaat, deze hebben namelijk geen volume-ID. + + "Sectorsize isn't 512 bytes, can't work on this disk", de + sectorgrootte is niet 512 bytes. Deze foutmelding zal + waarschijnlijk nooit voorkomen maar voor de zekerheid is + deze wel ingebouwd. + + "Not enough free memory segments for Dirsort", er zijn geen + vrije geheugen segmenten aanwezig. Waarschijnlijk is er een + te grote ramdisk aangemaakt, deze zal dus verkleind moeten + worden. Het kan ook zijn dat Memman alle segmenten in + gebruik heeft, dan zal het geen zin hebben om de ramdisk te + verkleinen. + + "This program works only under MSX-DOS 2", er wordt + geprobeerd om Dirsort te laden in de MSX-DOS 1 omgeving. + + "The Mapper Support Routines aren't available", deze + foutmelding zal waarschijnlijk nooit voorkomen aangezien + Dirsort alleen met MSX-DOS 2 kan werken. Maar er moet nu + eenmaal gecontroleerd worden of de Mapper Support Routines + aanwezig zijn. + + + I N S T E L L E N K L E U R E N + + De kleuren en de cursorsnelheid kunnen met het bijgeleverde + programma DSORTINS.BAS aangepast worden. De kleuren zijn de + standaard-MSX kleuren, dus 1=zwart, 2=groen, + 3=lichtgroen,..., 14=grijs en 15=wit. + + + Disclaimer: Schade die voortvloeit uit het gebruik van + Dirsort is niet te verhalen op Stichting Sunrise of + ondergetekende, gebruik op eigen risico. + + Voor eventuele updates of vragen en opmerkingen kunt U + contakt opnemen met BBS Club Gouda. Voor vragen of + opmerkingen kunt U dan een berichtje voor mij achterlaten + (priv�). + + Rainier Maas diff --git a/sunrise_special/4/Easy BDOS.md b/sunrise_special/4/Easy BDOS.md new file mode 100644 index 0000000..b577f7a --- /dev/null +++ b/sunrise_special/4/Easy BDOS.md @@ -0,0 +1,403 @@ + E A S Y B D O S + + + Opm: Ik ga er in dit artikel van uit dat de lezer een + behoorlijke kennis van de BDOS bezit. + + Het aansturen van een diskdrive is een zeer lastig + karweitje. Zelfs ervaren programmeurs zullen meerdere malen + verwensingen aan bepaalde chipfabrikanten maken tijdens het + schrijven van software om een FDC (Floppy Diskdrive + Controller) aan te sturen. Dat is ��n van de redenen waarom + de BDOS standaard in MSX zit. De BDOS maakt elke kennis van + FDC's overbodig voor het aansturen van een diskdrive. De + BDOS software schept als het ware een interface van en naar + de gebruiker dat vele malen eenvoudiger is dan het direkt + aansturen van de FDC. (Nvdr: en het werkt ook nog op bijna + alle computers.) + + We zijn de ontwerpers van de BDOS dan ook eeuwig dankbaar + voor deze vriendelijke geste, maar er schort nog het ��n en + ander aan dit 'gebruikersvriendelijke' interface. Het + schrijven van een goede routine om een file van disk te + laden is nl. niet zo eenvoudig als de BDOS doet vermoeden. + Om dit te bewijzen zal ik eerst maar een voorbeeld geven van + de meest eenvoudige methode om een file te laden. + + Stel we willen een MoonBlaster muziekstuk inladen. Een + dergelijke file is praktisch altijd kleiner dan 16 kB. Met + deze kennis kan dan de volgende routine geschreven worden. + + LD_MBM: LD C,15 + LD DE,FCB + CALL &HF37D ; Open file om eruit te lezen + INC A ; If A=255, then error + JR Z,NO_OK ; Fout tijdens openen file + LD HL,0 + LD (FCB+12),HL ; Zet start(lees)blok op 0 + INC HL + LD (FCB+14),HL ; Zet recordlengte op 1 + LD C,26 + LD DE,MUSADR + CALL &HF37D ; Leesadres van file is MUSADR + LD C,39 + LD DE,FCB + LD HL,&H4000 ; Lees max. 16kB + CALL &HF37D ; Lees blok + DEC A ; A=1, then error + JR NZ,NO_OK + OK: : + : + RET + + NO_OK: : + : + RET + + FCB: DB 0 + DM "MB_MUSIC","MBM" + DW 0,0 + DW 0,0,0,0,0,0,0,0 + DW 0,0 + DB 0 + + Na de bestudering van dit 'programma' valt de + foutafhandeling van de feitelijke laadaktie (C=39) op. + Indien de BDOS hier een foutmelding geeft is de laadaktie + goed? Dit komt omdat we probeerden 16 kB in te laden terwijl + we weten dat de file per definitie kleiner dan 16kB is. + Zelfs de BDOS zal niet voorbij het eind van een file + proberen te lezen en geeft dientengevolge een foutmelding. + + Deze routine rammelt werkelijk aan alle kanten en kan veel + beter geschreven worden. Dit kan door de recordlengte gelijk + te maken aan de bestandslengte. Na het openen van de file + staat de bestandslengte in het FCB. Door deze in de + recordlengte te kopi�ren en daarna bij de laadaktie niet + 16 kB in te lezen, maar 1 record gaat het wel goed. + + Dit soort routines heeft verder als nadeel dat ze absoluut + niet universeel inzetbaar zijn. Voor het laden van muziek en + andere data gaat het wel, maar om graphics behoorlijk te + laden moet meer uit de kast gehaald worden. Het zou er op + neerkomen dat er voor elke soort te laden file een aparte + routine zou moeten komen met eigen error handling. U + begrijpt, dit levert enorme listings op met routines die + toch heel erg veel op elkaar lijken. + + Wat ik hiermee probeer aan te tonen is dat de BDOS een + uiterst noodzakelijk stukje software is, maar dat er bij het + gebruik toch nog wat haken en ogen aan zitten. Naast de + normale BDOS error handling (BDOS uitvoer via het A + register) is er nl. ook nog de error pointer hook die bij + ernstige diskdrive fouten aangeroepen wordt. Probeer maar + eens een file te cre�ren met de diskdrive protect schuif + open. Uw machinetaal programma zal zonder pardon naar BASIC + terugkeren (een verbijsterde programmeur achterlatend). + + + K A N H E T E E N V O U D I G E R ? + + Natuurlijk, is dan mijn antwoord. Praktisch is gebleken dat + het goede gebruik van de BDOS helemaal niet zo eenvoudig is + als de makers doen geloven. Wat we nodig hebben is software + die een nieuw interface tussen de diskdrive en de gebruiker + vormt waardoor de gebruiker absoluut geen kennis van de BDOS + meer nodig heeft. Het enige waar de gebruiker zich nog om + hoeft te bekommeren is dat hij ervoor moet zorgen dat de + gegevens op de juiste plaats terecht komen. + + Laten we eerst maar eens gaan kijken wat deze software moet + doen. Praktisch blijkt dat 95% van alle BDOS gebruik beperkt + blijft tot het laden of bewaren van gegevens. Het heeft + praktisch dus ook weinig zin om onze nieuwe besturings + software iets anders te kunnen laten doen. + + Foutmeldings uitvoer van de routines kan beter met de Cy + flag gedaan worden dan met het A register (zoals de BDOS + doet). Dit komt omdat via de Cy flag onmiddelijk een + spronginstruktie gedaan kan worden terwijl met het A + register eerst een flag zet instruktie gedaan moet worden. + + + E A S Y B D O S F U N C T I E S + + De nu te beschrijven routines zijn terug te vinden in de + file EASYBDOS.ASC die op deze disk te vinden is. De + verzameling routines heet de fileshell omdat ze nl. als een + schil om de BDOS heen zitten. + + De routines laten nog te wensen over. Zo kan er maar 1 file + tegelijkertijd open staan, terwijl de BDOS er veel meer kan + hebben. Het toevoegen van een dergelijke optie zou voor de + gemiddelde programmeur echter weinig problemen op moeten + leveren. Ik kan me voorstellen dat FOPEN en FCREAT een + nummer in het A register teruggeven die dan bij resp. FBLKRD + en FBLKWR weer meegegeven moeten worden. Elk nummer staat + dan voor een bepaald FCB waarvan het adres dan wel door de + routines berekent kan worden. Let er daarbij wel op dat de + variabele FSTAT dan niet meer naar behoren funktioneert, dus + ook dit moet dan aangepast worden. + + Een andere beperking is die dat de maximale lengte van een + te lezen file 65535 bytes is. Deze beperking is echter + redelijk eenvoudig op te lossen. Het gebruik van deze + routines is in eerste instantie ook alleen maar bedoeld voor + demo's en kleine utilities. Voor het wat serieuzere werk zal + ik deze twee beperkingen er nog wel eens uit halen. + + + F I L E S H E L L I N S T A L L + Name: FINSTL + In : A, (see BIOS routine &H24) + Out : Cy, on error + + Deze routine installeert de software. Naast het + initialiseren van enkele systeemvariabelen buigt deze + routine de BDOS pointer error hook af zodat bij een ernstige + fout niet meteen naar BASIC gesprongen wordt. Elke aanroep + die vanaf nu rechtstreeks naar de BDOS gemaakt wordt, zal + afgevangen worden zodat de error handling ook dan actief is. + A moet bij invoer de slot en subslot waarden van page 1 + bevatten. Het programma zou dit ook zelf wel uit kunnen + zoeken, maar dat gaat hier wat ver. + + Heb je bv. de BASIC ROM nog 'aan' staan, dan is de aanroep + als volgt: + + LD A,(&HFCC1) ; Slot en subslot van MAIN-ROM + CALL FINSTL + RET C ; Error + + Is de BASIC ROM vervangen door RAM geheugen, dan is de + aanroep: + + LD A,(&HF342) ; Slot en subslot van MAIN-RAM + CALL FINSTL + RET C + + Indien FINSTL niet uitgevoerd wordt zal elke andere + fileshell routine aanroep onmiddelijk een foutmelding terug + geven. + + + F I L E S H E L L R E S E T + Name: FRESET + In : nothing + Out : Cy, on error + + Met FRESET kan de fileshell software weer van de BDOS + verwijderd worden. De BDOS wordt niet langer afgetapt en + error handling wordt niet meer gedaan. Indien er nog een + schrijf file open staat wordt deze eerst automatisch + gesloten. + + + O P E N F I L E + Name: FOPEN + In : HL, filename address + OUt: Cy, on error + + FOPEN moet aangeroepen worden wanneer een file gelezen moet + worden (net als bij de BDOS overigens). HL moet bij invoer + wijzen naar de filenaam. Dit ziet er als volgt uit: + + LD HL,MBMNME + CALL FOPEN + RET C + : + : + + MBMNME: DM "MB_MUSIC","MBM" + + De filenaam MOET 11 karakters lang zijn. Indien de naam niet + 8 karakters lang is moet de naam met spaties aangevuld + worden. Ditzelfde geldt ook voor de extensie. + + + F I L E B L O C K R E A D + Name: FBLKRD + In : DE, blocklength + HL, load address + Out : Cy, on error + A , ="r" if file is loaded. + + FBLKRD leest een blok van een geopende file. Indien de + blocklengte groter is dan de (resterende) filelengte past de + routine deze automatisch aan. HL mag alle waarden hebben + behalve het adresgebied tussen &H4000 en &H8000 (page 1). + Deze beperking wordt door het MSX systeem opgelegt. Sommige + programmeurs schijnen dit nog steeds niet te weten. Indien + de file helemaal geladen is staat bij uitvoer het karakter + "r" in register A (De r van 'ready'). Willen we nu een file + laden die groter is dan 16 kB in blokken van 16 kB dan gaat + dat bv. als volgt: + + LD A,1 + LOOP: OUT (&HFE),A ; Zet memory mapper + PUSH AF + LD DE,&H4000 ; Lees max. 16kB blok + LD HL,&H8000 ; Vanaf adres &H8000 + CALL FBLKRD + EX AF,AF ; Bewaar uitvoer + POP AF + INC A ; Volgende memory map. pagina + EX AF,AF ; Haal uitvoer weer op + RET C ; Error + CP "r" ; Klaar met laden + RET Z + EX AF,AF + JR LOOP + + + C R E A T E F I L E + Name: FCREAT + In : HL, filename address (See FOPEN) + Out : Cy, on error + + Met FCREAT kan een nieuwe file gemaakt worden (net als bij + de BDOS). + + + F I L E B L O C K W R I T E + Name: FBLKWR + In : DE, blocklength + HL, startaddress + Out : Cy, on error + + Deze routine werkt in principe net zo als de block laad + routine, met het verschil dat de file automatisch gesloten + wordt na het optreden van een foutmelding. + + LD DE,&H1000 ; Schrijf 4kB + LD HL,&H8000 ; Vanaf adres &H8000 + CALL FBLKWR + RET C ; Fout opgetreden + LD DE,&H1000 + LD HL,&HB000 + CALL FBLKWR + RET C + CALL FCLOSE ; Sluit file indien klaar + XOR A ; Maak Cy laag + RET + + + C L O S E F I L E + Name: FCLOSE + In : Nothing + Out : Nothing + + Deze routine doet niets meer dan het aanroepen van het BDOS + close commando en is nodig om een net aangemaakte file af te + sluiten. + + + C H A N G E D I S C + Name: CHNDSK + In : A + Out : Nothing + + Change disk is een extraatje. Indien A bij aanroep 0 is + wordt de boodschap "Insert source disk" op het scherm gezet + en in alle andere gevallen "Insert destination disk". Daarna + wordt gewacht tot de spatiebalk ingedrukt wordt. Indien twee + keer achter elkaar een source disk aangevraagd wordt zal de + routine meteen terug springen zonder een tekst op het scherm + te zetten. + + + De nu volgende routines zijn niet voor de gebruiker bedoeld, + maar ik noem ze toch maar even. + + INTOFF: + Deze routine zet de VDP interrupt (50/60 Hz) generator uit. + Hierdoor gaat het laden (vooral op trage Sony's) sneller. + + INTON: + Laat zich raden. + + FBDOS: + Dit is de routine waar elke BDOS aanroep na aanroep van + FINSTL naar toe springt. + + ERRCDE: + Dit is de routine waar naartoe gesprongen wordt bij een BDOS + error handling via de pointer hook. Deze routine heeft een + 'Abort, Retry' optie ingebouwd en voorkomt dat bij een + dergelijke fout naar BASIC gesprongen wordt. De routine + wordt bv. aangeroepen wanneer de disk uit de drive gehaald + wordt tijdens bv. een laadaktie. + + !!! WAARSCHUWING !!! + + Net als enkele belankrijke variabelen (vanaf PG1SET) mag + deze routine niet op page 1 gemapt worden. Zet deze routine + bij voorkeur op page 3 (vanaf &HC000). + + Bij een abort wordt de stack hersteld en worden de slot en + subslot instellingen van page 1 hersteld naar de waarde die + bij FINSTL opgegeven is. Dit moet omdat de BDOS ROM zich nl. + op PAGE 1 nesteld tijdens disk akties. Hierna wordt de stack + hersteld en geeft de routine een standaard BDOS error terug + (A=1). Met deze methode wordt terugspringen naar BASIC + voorkomen. + + Bij een Retry wordt het C register 1 gemaakt waardoor de + BDOS de disk aktie zal proberen te herhalen! + + PRTERR: + Deze routine wordt gebruikt door alle fileshell routines om + foutmeldingen op het scherm te zetten. Invoer gaat via het A + register waar het foutnummer in staat. Deze methode zorgt + ervoor dat de feitelijke fileshell routines korter en + overzichtelijker worden. + + + Als laatste zijn er dan nog de fileshell variabelen. + Vanaf PG1SET mogen de variabelen niet meer op PAGE 1 gemapt + zijn. Zet deze dus het liefst vanaf adres &HC000. + + FSTAT: + Hierin staat de fileshell status. De opbouw is als volgt: + Bit 0, hoog, dan is FINSTL uitgevoerd (fileshell aktief) + Bit 1, hoog, dan is de huidige file open voor lezen + Bit 2, hoog, dan is de huidige file open voor schrijven + (Bit 1 en 2 kunnen dus nooit gelijktijdig hoog zijn) + + CURDRV: + Huidige drive. + 255, dan is CHNDSK nog nooit aangeroepen + 0 , dan is de huidige disk de 'source disc' + 1 , dan is de huidige disk de 'desination disc' + + FLELEN: + Het aantal nog te LEZEN bytes van een open file. + + _##ERR: + Bewaarplaats van de oude BDOS error double pointer + + OLDDOS: + Bewaarplaats van oude BDOS aanroep hook + + PG1SET: + Bewaarplaats van bij FINSTL opgegeven slot instellingen + + SP_SAV: + Bewaarplaats voor StackPointer register + + FCB: + Het FCB + + + Dat is het dan. Probeer de listing eens uit. De minste + problemen zullen optreden als de complete listing vanaf + &HC000 begint. Lees ook eens het artikel over de BDOS error + handling om wat gedetailleerdere informatie te krijgen. Ik + zou zeggen, klieder naar hartelust in het gegeven + programmeervoer en haal de twee eerder genoemde beperkingen + er zelf eens uit. Let vooral op hoe snel het met deze + routines mogelijk is om complete laad of save routines in + elkaar te gooien en hoe klein deze dan zijn. Tot de volgende + preek. + + Alex van der Wal diff --git a/sunrise_special/4/GetDisk 2.0.md b/sunrise_special/4/GetDisk 2.0.md new file mode 100644 index 0000000..d6f383f --- /dev/null +++ b/sunrise_special/4/GetDisk 2.0.md @@ -0,0 +1,126 @@ + G E T D I S K 2 . 0 + + + Op deze Sunrise Special staan de nieuwe versies van de + harddisk utility's die op de vorige SRS hebben gestaan. Met + deze programma's kan een spel dat een (of meer!) hele + diskette(s) beslaat als een file op de harddisk worden + opgeslagen en worden opgestart. + + + A A N P A S S I N G E N + + Ik heb de programma's geheel herschreven en nu gebruik + gemaakt van DOS2 system calls. Hierdoor is de snelheid + verbeterd, maar het werkt nu natuurlijk niet meer onder + DOS1, maar harddiskgebruikers onder DOS1 kunnen natuurlijk + nog gewoon de oude versie blijven gebruiken. Maar een + harddisk onder DOS1 is als een normaal mens achter een + Amiga; er zullen wel niet veel DOS1 HD gebruikers meer zijn. + + + V E R D E R E V E R A N D E R I N G E N + + Het gedeelte dat de diskette inleest en op de harddisk zet + is nu gecombineerd tot de COM-file GETDISK.COM i.p.v. + GETDISK.BAS en GETDISK.BIN. + + Bij het opstarten van GETDISK.COM wordt er eerst gevraagd + van welke drive de diskette ingelezen moet worden. Daarna + wordt om het aantal diskettes gevraagd en als laatste onder + welke naam de file bewaard moet worden. + + Bij zowel GETDISK.COM als START.COM kan er nu een path + worden opgegeven. START.COM handelt nu de phydio BIOS call + beter af, waardoor meer spellen onder DOS2 draaien. + + Als laatste is er een programma ADAPT.COM bij gekomen dat + een bestand dat al is opgeslagen met GETDISK.COM langsloopt + om te kijken of de diskrom soms rechtstreeks wordt + aangeroepen en zonodig deze calls verandert. Gebruik + ADAPT.COM alleen als een spel niet met START.COM opgestart + kan worden, zoals bij de spellen van Bit2. + + + A L L E S O P E E N R I J T J E + + - Start het programma GETDISK.COM op (zonder parameters) en + geef op welke driveletter de diskdrive heeft. + - Tel nu hoeveel diskettes het spel is dat op harddisk gezet + moet worden (vergeet niet de evt. userdisk mee te + rekenen). + - Geef dit aantal op en geef de naam (met evt. drive en + path) op waaronder het spel bewaard moet worden. + - Probeer het spel op te starten met START + drive:\path\filename.ext. + - Loopt de computer vast, reset dan en probeer ADAPT + drive:\path\filename.ext + - Start het spel nog een keer op met START.COM + - Werkt het nu nog steeds niet, dan kan het spel helaas + (nog) niet op de harddisk. + + + D E S P E L L E N + + De spellen in dit lijstje werken met GETDISK. Als je nog een + spel gevonden hebt, kun je dat laten weten via Sunrise BBS + Nuth of de postbus, t.a.v. Kasper Souren. + + Compile: Aleste Special + Golvellius 2 + Gorby's Pipeline + Nyanpi + Puyo Puyo + Randar 3 + Rune Master 1 + Rune Master 2 + Rune Master 3 + Supercooks + Konami: F1-Spirit 3D + Momonoki house: Peach Up summary 2 + Peach Up 8 + DBP: Tetris + Falcom: Ys 3 + Bit2: Quinpl (ADAPT.COM gebruiken) + Nyancle (ADAPT) + Wolfteam: Niko Niko + ?: Herzog + ?: Haradius + ?: Pacmania + + + Het moge duidelijk zijn dat al deze spellen onbeveiligd + zijn. Dat wil zeggen: ze moeten met FastCopy te kopi�ren + zijn door gewoon track 0 t/m 79 te kopi�ren. + + Van Compile werkt tot nu toe alleen Aleste 2 niet. Ik + vermoed dat ook alle DiscStations en Randar 1 en 2 goed + zullen functioneren. + + Ik vermoed dat Ys 1 en Ys 2 ook werken, maar dit kan ik niet + controleren omdat ik deze spellen niet bezit. + + Noot: alleen spellen die helemaal op sector staan werken. + Spellen die niet alleen op sector staan, maar ook files + laden, kunnen niet met de huidige versie van GETDISK worden + gebruikt. Hierdoor vallen helaas alle MicroCabins weg. + + + PUTDISK + + Op deze Special staat ook PUTDISK.COM. Hiermee kun je een + spel weer terug op diskettes zetten. Handig als je even de + userdisk nodig hebt om ergens anders te spelen. + + + R800 + + Spellen die de MSX-MUSIC chip rechtstreeks aansturen zullen + geen rekening hebben gehouden met de R800. Daarom is het + geluid verminkt als het spel onder R800 gedraaid wordt. + Spellen die alleen de PSG gebruiken (Ys 3, Herzog) werken + wel goed. Ook zijn er spellen die de FM BIOS gebruiken, + bijv. Pacmania, en die werken dan wel goed. + + Michel Shuqair + Kasper Souren diff --git a/sunrise_special/4/HD Indelen.md b/sunrise_special/4/HD Indelen.md new file mode 100644 index 0000000..b4ae85b --- /dev/null +++ b/sunrise_special/4/HD Indelen.md @@ -0,0 +1,110 @@ + H D I N D E L E N + + + Het indelen van een harddisk kan natuurlijk heel snel + gebeuren. Maar het is verstandiger om even erover na te + denken. Er bestaat nl. de kans dat je veel files niet meer + kunt vinden na verloop van tijd, als je gewoon lukraak + subdirectory's aanmaakt. + + Dat er dan een programma als FileFind bestaat, doet daar + niks aan af. Het is onhandig om telkens als je iets nodig + hebt weer FF te moeten gebruiken. + + Ook kun je denken aan welke schil je wilt gebruiken. Gewoon + onder MSX-DOS werken met een paar batchfiles of een GUI + (Graphical User Interface) als MSX-View of Easy. + + + P A R T I T I E S + + Om te beginnen bij het begin: je moet de harddisk opdelen in + partities (high level formatteren genaamd; meestal is de + harddisk al low level geformatteerd). Je kunt, als je een + harddisk kleiner dan of gelijk aan 32 MB hebt, gewoon ��n + partitie aanmaken. Maar dit is niet erg slim. Je krijgt dan + vrij grote clusters, soms zelfs van 32 kB. Hierdoor wordt je + harddisk niet erg snel. + + Het is dus verstandig om een kleine A: partitie aan te maken + met daarop allerlei programma's (aatjes) die je vaak + gebruikt. Ikzelf heb gekozen voor 4 MB. Als je dan de FAT op + 12 sectoren zet, heb je clusters van 1 kB. + + + F A T G R O O T T E + + Je kunt het beste altijd een FAT van 12 sectoren nemen, dan + is de clustergrootte het kleinst. Dit komt ook weer de + snelheid ten goede. Maar niet alleen de snelheid. Bij + clusters van 32 kB kost ook een file van ��n byte je 32 kB. + + De volgende partitie(s) kun je dan natuurlijk wel zo groot + mogelijk maken. De max. grootte van een partitie is 32 MB. + Als je het �cht maximaal neemt, krijg je clusters van 32 kB. + Ik heb daarom even gekeken of dit niet beter kon. En het k�n + beter. Als je als grootte 32686 kB neemt (bij FDISK van MK), + krijg je met een FAT van 12 sectoren clusters van 16 kB. + + Ik heb op mijn 80 MB HD gekozen voor de volgende indeling: + + A: 4096 kB 2 sectoren per cluster + B: 32686 kB 16 sectoren per cluster + C: 32686 kB 16 sectoren per cluster + D: 13456 kB 8 sectoren per cluster + + R O O T D I R + + Je moet voorkomen dat er veel files in de rootdirectory + komen te staan. Je kunt het beste alleen COMMAND2.COM, + MSXDOS2.SYS, AUTOEXEC.BAT en REBOOT.BAT in de root laten + staan. Dit is niet alleen voor de overzichtelijkheid, maar + komt ook de snelheid ten goede. Bij het opstarten worden de + juiste files meteen gevonden. + + De rootdirs van de andere partities kun je het beste + helemaal leeg laten. Daar mogen eigenlijk alleen maar + subdirectory's in staan. + + Bij FDISK kun je daarom ook het beste de dirgrootte op 64 + bestanden zetten. Dit is het kleinste. + + + S U B D I R S + + Zoals gezegd komen op A: programma's die vaak gebruikt + worden. Ik heb zelf de volgende (1e graads) subdirectory's + op A: + + BASIC - BASIC tools (bijv. Flexkist, KUN-BASIC) + BATCH - batchfiles + CRUNCH - allerlei crunchers en decrunchers + MEMMAN - MemMan + ML - machinetaal tools (bijv. GEN80, MSXDEBUG) + UTILS - allemaal utility's + VIEW - MSX-View + + In MEMMAN zit weer de subdirectory TSRS, dit om het een + beetje overzichtelijk te houden. Als er 30 TSR's tussen + andere files staan, wordt het een beetje onduidelijk. + + UTILS moet ik nog eens goed indelen: bepaalde (2e graads) + subdirectory's voor bijv. tekst-tools (TED, wordcount) en + turbo R tools (READKANA, ROMTURBO). + + MSX-View bevat uiteraard allerlei subdirs met files die + bestemd zijn voor View zelf. + + + A N D E R E P A R T I T I E S + + Ik heb het zelf nog niet goed ingedeeld, omdat ik nog mijn + BBS op deze HD heb staan. Maar zodra ik weer "echt" online + ben, zal ik het BBS op een aparte HD zetten (20 MB is meer + dan genoeg voor een BBS). + + Dan wil ik op B: muziek (MOD-files, MoonBlaster, + Soundtracker, SME 3) zetten, op C: tekst, informatie en + (mijn) sources en op D: spellen. + + Kasper Souren diff --git a/sunrise_special/4/HEX Printen.md b/sunrise_special/4/HEX Printen.md new file mode 100644 index 0000000..2b7699f --- /dev/null +++ b/sunrise_special/4/HEX Printen.md @@ -0,0 +1,75 @@ + N O G M A A L S H E X P R I N T E N + + + Op Sunrise Special #3 stond een tekst van mij over het + printen van een binair, hexadecimaal of decimaal getal in + ML. De decimale routine was goed en de binaire zeer mooi, + maar de hexadecimale was nogal eh... vreemd geprogrammeerd. + Dat komt ervan als je na 2:00 's nachts nog teksten voor de + Special gaat schrijven! + + Om het goed te maken hierbij een fatsoenlijke routine om een + getal hexadecimaal af te drukken. Onderstaande source stuurt + de waarde in A hexadecimaal naar het scherm. + + PRTHEX: LD C,A ; bewaar A voor andere helft + AND &HF0 ; bovenste nibble + RRCA + RRCA + RRCA + RRCA ; verschuif naar onderste + CALL UITHEX ; printen + LD A,C ; oude waarde weer terug + AND &H0F ; onderste nibble + CALL UITHEX ; printen + RET + UITHEX: ADD A,"0" + CP "9"+1 ; is het een cijfer? + JP C,CIJFER ; ja, dan printen + ADD A,"A"-"9"-1 ; nee, dan letter van maken + CIJFER: CALL &HA2 ; BIOS routine CHPUT + RET + + + S P A G H E T T I + + Dit is een nette routine. Er zullen echter programmeurs zijn + die zeggen dat het sneller kan. Dat kan ook wel, en het + werkt ook wel, maar het is dan niet zo netjes meer. Je + krijgt dan het volgende: + + PRTHEX: LD C,A + AND &HF0 + RRCA + RRCA + RRCA + RRCA + CALL UITHEX + LD A,C + AND &H0F + UITHEX: ADD A,"0" + CP "9"+1 + JP C,&HA2 + ADD A,"A"-"9"-1 + JP &HA2 + + Het is korter en sneller, en toch zou ik het nooit zo + programmeren. In zo'n kleine routine kun je niet zo gauw van + spaghettistijl spreken, maar dit begint er aardig op te + lijken. De routine roept namelijk halverwege zijn staart al + een keer aan, en dat soort dingen vallen nu eenmaal onder de + noemer "spaghetti". Ook het vervangen van CALL &HA2 en RET + door een JP en is niet echt netjes, en het weglaten van de + tweede CALL UITHEX al helemaal niet. + + Maar goed, welke routine u ook kiest, het is in ieder geval + beter dan die maffe routine van de vorige keer (al was dat + geen spaghetti!). + + Stefan Boer + + + Nvdr. Hier verschillen Stefan en ik duidelijk van mening. + Vandaar dat ik deze tekst toch laat staan. In het stukje + over een goede random routine gebruik ik nl. de routine die + volgens Stefan "fout" is. diff --git a/sunrise_special/4/Index registers.md b/sunrise_special/4/Index registers.md new file mode 100644 index 0000000..fb3f31c --- /dev/null +++ b/sunrise_special/4/Index registers.md @@ -0,0 +1,198 @@ + I N D E X R E G I S T E R S + + + De Z80 is uitgerust met twee indexregisters, IX en IY. Deze + registers worden door beginnende ML programmeurs vaak niet + of op de verkeerde manier gebruikt. In dit artikel zal ik + uitleggen waarvoor je de indexregisters goed kunt gebruiken + en hoe, en waarvoor niet. Eerst even een korte uitleg voor + degenen die nog helemaal niets van IX en IY weten. + + + I E N X ? + + De registers IX en IY zijn beiden 16 bits, maar ze kunnen + (bij de Z80 althans) niet op dezelfde manier worden + gesplitst als de andere 16 bits registers: BC, DE en HL. Het + is dus onzin om het hoge deel van IX met I aan te duiden, + vooral omdat het I register al bestaat en een totaal andere + functie heeft. Bij de R800 kunnen IX en IY wel worden + gesplitst, maar dat wordt aangeduid met IXL en IXH, resp. + IYL en IYH. IX betekent gewoon Indexregister X. + + + G E I N D E X E E R D E A D R E S S E R I N G + + De naam zegt het al: IX en IY kunnen worden gebruikt voor + ge�ndexeerde adressering. Dit werkt ongeveer hetzelfde als + indirecte adressering, met het verschil dat er bij het door + het register gegeven adres nog een constante wordt opgeteld. + Dit klinkt misschien erg ingewikkeld, maar met een simpel + voorbeeld is het al snel duidelijk hoe het werkt. + + LD IX,TABEL + LD A,(IX+3) + + Eerst wordt in IX het beginadres van een tabel geladen, en + daarna wordt de vierde (!) byte uit die tabel in A geladen. + Bijna alle instructies met HL en (HL) zijn er ook voor IX en + IY, waarbij (HL) dan wordt vervangen door (IX+d). Dit was + overigens niet de slimste manier om dit te programmeren, het + volgende is niet alleen korter maar ook veel sneller: + + LD A,(TABEL+3) + + En zo kom ik bij het eigenlijke onderwerp van dit artikel: + wanneer heeft het zin om de indexregisters te gebruiken en + wanneer niet. + + + V A R I A B E L + + Eigenlijk is het heel simpel: het heeft alleen zin om de + indexregisters te gebruiken als de waarde van de index- + registers variabel is. + + Wat bedoel ik daarmee? Even terug naar het voorbeeld: + + LD IX,TABEL + LD A,(IX+3) + + De waarde van IX is hier niet variabel, die is namelijk + altijd gelijk aan TABEL. Daarom kan er dus beter een + absolute adressering worden gebruikt: + + LD A,(TABEL+3) + + Dit is niet alleen korter en sneller, je gebruikt bovendien + minder registers. Het heeft wel zin om de indexregisters te + gebruiken als de waarde van de indexregisters variabel is + Dit komt bijvoorbeeld voor bij tabellen die uit entry's zijn + opgebouwd die langer zijn dan 1 byte. Het is dan erg + makkelijk om IX of IY telkens naar het begin van een entry + uit de tabel te laten wijzen, want dan kunnen de gegevens + uit op zeer eenvoudige wijze uit die entry worden gehaald. + Ik zal proberen dit duidelijk te maken met een voorbeeld. + + + L E N G T E V A N E N T R Y + + De lengte van de entry is maximaal 128. d is g��n unsigned + byte, dus 255 is eigenlijk -1. Als het indexregister naar + het begin van de entry wijst, kunnen er 127 andere byte + boven het begin en 128 bytes onder het begin. + + + V E C H T R O U T I N E + + Als ik de vechtroutine voor Pumpkin Adventure III ga + schrijven, dan komen daar zeker indexregisters aan te pas. + Stel ik heb de volgende tabel met de gegevens van de + vijanden: + + ENDAT: DB 100,20,25 ; vijand #0 + DB 200,50,40 ; vijand #1 + DB 150,30,35 ; vijand #2 + + ENDAT staat voor ENemy DATa, de getallen zijn achtereen- + volgens power, strength en defense. In werkelijkheid zijn er + natuurlijk veel meer vijanden en veel meer gegevens per + vijand. + + De lengte van een entry in deze tabel is 3 bytes. Het begin + van de vechtroutine zou er dan als volgt uit kunnen zien: + + ENEMY: LD B,A + ADD A,A + ADD A,B ; A=A*3 + LD C,A + LD B,0 + LD IX,ENDAT + ADD IX,BC + + Bij aanroep van de routine staat in A het nummer van de + vijand. We vermenigvuldigen dit eerst met de lengte van een + entry (3) en tellen dat vervolgens bij het beginadres van de + tabel op. In IX staat nu het beginadres van de entry dat bij + de juiste vijand hoort. Het is nu heel eenvoudig om power, + strength en defense uit te lezen, want op (IX+0) staat de + power, op (IX+1) de strength en op (IX+2) de defense. Het is + hopelijk duidelijk dat IX hier een variabele waarde heeft, + die is immers afhankelijk van de gekozen vijand. + + Dit is ook wel met HL te programmeren, en dat is soms zelfs + iets sneller, maar dat is een stuk minder makkelijk omdat je + dan met INC en DEC instructies moet zorgen dat HL naar de + gewenste positie in de entry wijst. Als je bijvoorbeeld + eerst het gegeven op (IX+3) nodig hebt en daarna dat op + (IX+28), dan is dat met indexregisters een fluitje van een + cent, terwijl je met HL iets als + + LD BC,25 + ADD HL,BC + + zult moeten gaan gebruiken, waarbij je dus ook nog het BC + (of DE) register nodig hebt. Bovendien is het prettig om HL + vrij te hebben voor andere zaken. + + De indexregisters kunnen dus zeer goed worden toegepast bij + het werken met tabellen waarvan de entry's uit meerdere + bytes bestaan. + + + L D I X , B C ? + + Een LD IX,BC instructie bestaat niet, en ook LD BC,IX, LD + DE,IY etc. zijn niet aanwezig. Gelukkig is daar een simpel + truukje voor: PUSHen en POPpen. Bijvoorbeeld: + + PUSH BC + POP IX ; LD IX,BC + + PUSH IY + POP DE ; LD DE,IY + + + S T R I N G S M E T U S R + + Ik zie vaak dat er een indexregister wordt gebruikt bij het + verwerken van een + + A$=USR(B$) + + aanroep vanuit BASIC. De BASIC interpreter zet in DE het + beginadres van drie bytes waar de string wordt beschreven + door de lengte op (DE) en het beginadres op (DE+1), en + springt vervolgens naar de ML routine. Je wilt nu de lengte + in B hebben en het beginadres van de string in DE. Dit wordt + vaak zo geprogrammeerd: + + PUSH DE 1 11 + POP IX 2 14 + LD B,(IX+0) 3 19 + LD E,(IX+1) 3 19 + LD D,(IX+2) 3 19 + --- ---- + 12 82 + + Dit zijn 12 bytes en 82 T-states. Het kan echter korter: + + EX DE,HL 1 4 + LD B,(HL) 1 7 + INC HL 1 6 + LD E,(HL) 1 7 + INC HL 1 6 + LD D,(HL) 1 7 + --- --- + 6 37 + + Dit is ��n regel meer in assembly, maar het zijn slechts 6 + bytes en 37 T-states. Dus twee keer zo kort en meer dan twee + keer zo snel. Hoewel de waarde van IX hier wel variabel is, + is het hier dus toch beter om HL te gebruiken. HL had hier + toch geen waarde die je nog nodig hebt, en bovendien hoeven + de gegevens hier maar ��n keer en op volgorde te worden + gelezen. Het werken met indexregisters heeft vooral + voordelen als je de gegevens door elkaar nodig hebt. + + Stefan Boer diff --git a/sunrise_special/4/Kun-Basic Cursus.md b/sunrise_special/4/Kun-Basic Cursus.md new file mode 100644 index 0000000..47d06ca --- /dev/null +++ b/sunrise_special/4/Kun-Basic Cursus.md @@ -0,0 +1,435 @@ + K U N - B A S I C C U R S U S + + + Vorige keer had ik tegen Kasper Souren (hoofdredacteur van + jullie meest geliefde diskmagazine) gezegd dat ik deze keer + misschien een programma om vector-graphics te maken in BASIC + zou plaatsen. Helaas zag dhr. Souren dit als een belofte. + Dit programma heb ik wel al, het werkt ook, maar nog niet + helemaal zoals ik het wil. Ook heb ik te maken gehad met een + "disk-crash" waar dat programma op stond en ik had geen + kopie... Ik heb nu een cursus geschreven (in ��n deel) voor + het gebruik van de KUN-BASIC compiler, het programma dat ik + heb gebruikt voor het vector-graphics programma, voor + ALPHA.BAS (zie SRS #3) en ook voor de fractal-makers die op + deze disk staan. Voor deze cursus heb ik o.a. gebruik + gemaakt van de gegevens uit de MSX2+ handleiding van MK. + + De KUN-BASIC compiler (ik kort het vanaf nu af tot BC: Basic + Compiler) is een in gebruik snelle en handige compiler voor + het compileren (=naar machinetaal omzetten) van MSX-BASIC. + Door gebruik te maken van de BC worden uw BASIC programma's + vele malen sneller. In het geval van ALPHA.BAS heb ik + gemerkt dat de ronddraaiende balletjes op 7 MHz even snel + draaien als op 3.5 MHz. De snelheid werd dus enkel bepaald + door de VDP en niet meer door BASIC + + Er zijn verschillende versies in omloop: eentje voor MSX2 + computers en eentje die ook de MSX2+ commando's kan + compileren (waarempel uit mijn computer "gesloopt") (Nvdr: + geen commentaar.). Beide versies kunnen op disk of in ROM + staat. Disk-versies moeten met BLOAD"naam",R worden + opgestart, ROM versies worden met CALL BC [enter] vanuit + BASIC geactiveerd. + + Deze compiler heeft als voordeel dat je gewoon in MSX-BASIC + blijft en dat je zelf kunt kiezen welke delen van het + programma gecompileerd worden, zodat je toch ook + niet-compileerbare commando's in het zelfde programma kunt + gebruiken. (later meer hierover.) Bovendien hoef je niet + allerlei apparte programma's op te starten om het te + compileren. + + + D R I E I N S T R U C T I E S + + Om een programma te compileren zijn er 3 instructies + toegevoegd: + + CALL RUN + CALL TURBO ON + CALL TURBO OFF + + Noot: CALL kan ook als underscore, "_" ingetikt worden. + + CALL RUN compileert het hele BASIC programma dat in het + geheugen staat, bijvoorbeeld: + + 10 SCREEN 8 + 20 FOR I=0 TO 255 + 30 LINE(I,0)-(I,211),I + 40 NEXT I + + Nadat u dit heeft ingevoerd, kunt het programma eerst eens + gewoon RUNnen, en daarna CALL RUN [enter] intikken. De + uitvoer is precies het zelfde; van het compileren merkt u + niets, dat gaat behoorlijk snel. Na CALL RUN is de uitvoer + wel een stuk sneller. CALL RUN"filenaam" werkt (helaas) + niet. + + + N I E T - W E R K E N D E C O M M A N D O 'S + + Er zijn commando's die de compiler niet kan compileren. Dit + zijn vooral de commando's voor disk-drive, printer en + geluids-chips. Hieronder is een reeks van niet-compileerbare + commando's weergegeven. + + AUTO, BASE BLOAD, BSAVE, CALL, CDBL, CINT, CLEAR, CLOAD, + CLOSE, CONT, CSAVE, CSNG, CVD, CVI, CVS, DEFFN, DELETE, + DRAW, DSKF, EOF, ERASE, ERL, ERR, ERROR, EQV, FIELD, FILES, + FPOS, FRE, GET, IMP, INPUT#, KEYLIST, LFILES, LINE INPUT#, + LIST, LLIST, LOAD, LOC, LOF, LPRINT USING, LSET, MAXFILES, + MERGE, MOTOR, MKD$, MKI$, MKS$, NAME, NEW, ON ERROR GOTO, + OPEN, PLAY, PRINT#, PRINT #USING, PRINT USING, PUT KANJI, + RENUM, RESUME, RSET, SAVE, SPC, TAB, TRON, TROFF, WIDTH + + Het lijkt heel wat, maar het is in de praktijk best op te + vangen. Nadeel vind ik dat PLAY en DRAW niet gecompileerd + kan worden. (SOUND echter weer wel.) Als u de versie voor 2+ + op een MSX2 gebruikt worden de commando's SET SCROLL e.d. + toch gecompileerd, maar heeft geen uitwerking. Je kunt + echter wel gewoon horizontaal scrollen met SET SCROLL. Maar + VDP(24) werkt dan even makkelijk. + + + Om toch b.v. een andere breedte (WIDTH) te kiezen is het + volgende mogelijk: + + 10 WIDTH 40 + 20 CALL TURBO ON + 30 PRINT "...." + ... + ... + 100 CALL TURBO OFF + + Nu wordt alleen het stuk tussen CALL TURBO ON en CALL TURBO + OFF gecompileerd. Een ander voorbeeld: + + 10 SCREEN 8:SET PAGE 0,1 + + Regel 10 zou ook gecompileerd kunnen worden, maar is te + omslachtig.) + + 20 BLOAD"PICTURE.PIC",s + + BLOAD kan niet gecompileerd worden. + + 30 CALL TURBO ON + 40 SET PAGE 0,0 + 50 FOR I=0 TO 211 + 60 COPY(0,I)-(255,I),1 TO (0,0),0 + 70 NEXT I + + De regels hierboven worden snel uitgevoerd. + + 80 CALL TURBO OFF + 90 OPEN"GRP:" FOR OUTPUT AS#1 + 100 PRESET(10,200):COLOR 255 + 110 PRINT #1,"Mooi he?" + 120 GOTO 120 + + OPEN en PRINT# kunnen niet gecompileerd worden. + + + B E P E R K T E C O M M A N D O 'S + + Van sommige commando's kunnen niet alle opties of parameters + gecompileerd worden: + + CIRCLE Start- en eindhoeken en mate van afplatting kunen + niet gecompileerd worden. + COPY Alleen graphische copy. + DEFDBL Zelfde werking als DEFSNG. + DIM Moet als eerste na CALL TURBO ON staan of vooraan + in een programma. + END Springt naar de regel NA CALL TURBO OFF, stopt het + programma dus niet! + INPUT Maximaal INPUT van ��n variabele, dus niet "INPUT + A,B". + KEY Alleen ON KEY GOSUB en KEY(x) ON/OFF toegestaan. + LOCATE X en Y coordinaat moeten allebei gegeven worden. De + switch cursor aan/uit (LOCATE X,Y,s(0/1)) is niet + toegestaan. + NEXT Variabele moet er ALTIJD achter staan, dus NIET + alleen NEXT, maar b.v. NEXT I of NEXT X,Y. + ON Men zegt dat ON STOP GOSUB en ON INTERVAL=X GOSUB + niet werken, wegens een bug, maar ik heb niets + gemerkt. (Ik heb echter alleen de versie voor + MSX2+!) + PRINT De komma-functie werkt anders dan normaal. + PUT Alleen PUT SPRITE toegestaan. + SCREEN Alleen scherm-modus en sprite-grootte kunnen + opgegeven worden. + SET Alleen SET PAGE en SET SCROLL (2+ versie) + toegestaan. + STOP Zelfde werking als END + USR De parameter kan alleen maar een integer zijn. + VARPTR File-nummer kan niet gegeven worden als parameter. + + + Er zijn ook een paar nieuwe opties toegevoegd: + + '#I Staat voor INLINE. Hiermee kunt u stukjes + machinetaal eenvoudig tussenvoegen. Bijv.: + + 10 CALL TURBO ON + 20 DEFINT I + 30 I=1 + 40 '#I &H2A,I% + 50 '#I &HF3,&HCD,@70,&HFB + 60 END + 70 'SUBROUTINE + 80 .. + 90 RETURN + 100 CALL TURBO OFF + + Regel 40 betekent: LD HL,(i) ; I moet integer zijn.) + Regel 50 betekent: DI + CALL @70 ; CALL naar regel 70. Let op! + ; Wordt niet mee geRENUMd! + EI + + + '#C +/- Zet het zogenaamde CLIPPEN aan of uit. Clippen + houdt in dat als de waarde van een y-coordinaat + groter is dan het beeld aankan, b.v. groter dan + 211, er net gedaan wordt alsof de y-waarde gelijk + is aan de maximale y-waarde, in het voorbeeld dus + 211. Geldt niet voor PAINT en CIRCLE + + Voorbeeld: + + 10 CALL TURBO ON + 20 SCREEN 5 + 30 '#C- + 40 LINE(0,0)-(255,255) (y geCLIPt) + 50 IF INKEY$="" THEN 50 + 60 '#C+ + 70 LINE(0,0)-(255,255) (y niet geCLIPt) + 80 IF INKEY$="" THEN 80 + 90 CALL TURBO OFF (Kan weggelaten worden) + + + #N +/- Kijkt of de waarde van de variabele tijdens een + NEXT overloopt. Als #N+ gegeven is, wordt de fout + net zoals in normaal BASIC afgehandeld. + + Voorbeeld: + + 10 CALL TURBO ON + 20 FOR I%=0 TO 100000 + 30 NEXT I% + 40 CALL TURBO OFF + + Als u dit programma RUNt blijft het oneindig doorlopen, + omdat I% (een integer) nooit 100000 kan bereiken. Als u 15 + '#N+ invoegt eindigt het net zoals normaal in een "Overflow + in 30" Deze switch vertraagt de uitvoering van het + programma, gebruik het dus alleen als het nodig is. '#N- zet + deze controle-fuctie weer uit. + + + T I P S E N O P M E R K I N G E N + + In normaal BASIC kunnen "oneindige" programma's met + [CTRL][STOP] toch gestopt worden. Dit kan tijdens de uitvoer + van een gecompileerd programma niet! Voorbeeld: + + 10 PRINT"Hallo! "; + 20 GOTO 10 + + Als u dit gewoon RUNt kunt u het altijd afbreken met + [CTRL][STOP], maar als u dit CALL RUNt kan dat niet. De + enige mogelijkheid om toch te stoppen is de computer te + resetten of uit te zetten! En daarmee het verlies van uw + programma. Hier wat oplossingen van dit probleem: + + 10 PRINT"Hallo! "; + 20 IF INKEY$="" THEN GOTO 10 + + Nu zal het programma altijd afbreken zodra er een toets + wordt ingedrukt. Natuurlijk werkt "ON STOP GOSUB" ook, maar + dit vertraagt de snelheid van het programma. + + + Andere oplossing: + + Tik voor dat u begint de POKE&HFBB0,1 in. Nu kunt u altijd + met [CTRL][SHIFT] [GRAPH][CODE] het programma verlaten en + valt u terug in BASIC. Let op als u het programma onderbrak + terwijl u NIET in een tekstscherm was! Dan ziet u niets + meer. Tik dan SCREEN 0. + + + Nog een oplossing: + + Dit is meer een nood-oplossing, voor als er toch nog iets + mis is gegaan en u de computer hebt moeten resetten: dus na + een reset, tik dan in: POKE32770,128: POKE32769,1:LIST + [ENTER] Nu ziet u dat telekens de eerst regel van het + programma weergegeven wordt. Druk op [CTRL][STOP] om het + listen te onderbreken en tik dan ALLEEN het regelnummer van + de eerste regel in en druk op ENTER. Nu kunt u uw programma + normaal listen en op diskette wegschrijven. Als u dit gedaan + heeft, kunt u het beste weer resetten en het programma + gewoon met "LOAD" in te laden, voordat u verder gaat. + Voorbeeld: + + [reset] + POKE32770,128:POKE32769,1:LIST + 10 PRINT"Hallo! "; + 10 PRINT"Hallo! "; + 10 PRINT"Hallo! "; + 10 PRINT"Hallo! "; [CTRL][STOP] + Ok + 10 [ENTER] + list + 10 PRINT"Hallo! "; + 20 GOTO 10 + Ok + save "naam.bas",a + + + V R E E M D E D I N G E N + + De BC vindt een string-formule al snel te complex en zal dan + ook snel met de "String formula too complex"-error aankomen. + + Als er bij een goto naar een regel gesprongen wordt die niet + bestaat, zal de BC altijd de als fout-regel de regel met + CALL TURBO OFF geven. B.v. + + 10 CALL TURBO ON + 20 GOTO 25 + 30 PRINT "TJA..." + 40 CALL TURBO OFF + + RUN + Undefined line number in 40 + + Daar staat echter niets verkeerds. Zeker bij groter + programma's is de fout vaak moeilijk op te sporen. Hier een + truuk om de fout snel te vinden. + + RENUM 55555,55555,55555 + + Zorg ervoor dat er geen regelnummers na 55555 voorkomen, + anders gebeurt er wel wat. Er zal niets met uw listing + gebeuren, maar er wordt wel gemeld dat er naar een + niet-bestaande regel gesprongen wordt in regel 20. + + De disk-versies van de BC nemen de memory-map page 2 en 3 in + beslag, dus let op met een RAM-disk. Bij mijn ROM-versie heb + ik die problemen niet gehad. + + Nvdr: de ROM versie zet zichzelf ook in pagina 2 van de + memory mapper. Daarom is CALL BC nodig om te initialiseren. + KUN zit bij MSX2+'en op page 2 van het ROM. Dus van #8000 + tot en met #bfff. Bij de turbo R kun je met het programma + READKANA (zie deze disk) een programma in de DRAM laden, dan + kost het alleen je Kanji ROM, als je de DRAM mode aan hebt. + + Het gecompileerde programma wordt ook in page 2 en 3 gezet, + net als het bron-BASIC programma, maak het bron-programma + dus niet te groot. + + Alle variabelen BUITEN het TURBO blok zijn niet toegankelijk + IN het TURBO blok en vice versa. Doc integers (zowel enkele + variabelen als arrays) kunnen wel meegenomen worden naar het + TURBO blok en weer naar buiten. Voorbeeld: + + 10 DIM A%(5) + 20 B%=4:C%=3 + 30 FOR I=1 TO 5:A%(I)=4-I:NEXT I + 40 CALL TURBO ON ( A%() , B% ) + 50 B%=B%+1 + 60 FOR I=1 TO 5:A%(I)=I+3:NEXT I + 70 PRINT B%,C% + 80 FOR I=1 TO 5:PRINT A%(I); + 90 CALL TURBO OFF + 100 PRINT B%,C% + 110 FOR I=1 TO 5:PRINT A%(I); + + RUN + 5 0 + 4 5 6 7 8 + + 5 3 + 4 5 6 7 8 + + + Dubbele precisie-variabelen IN het TURBO blok hebben een + nauwkeurigheid van 4,5 decimalen. Voorbeeld: + + 10 CALL TURBO ON + 20 PI=3.1415926535897 + 30 PRINT PI + 40 CALL TURBO OFF + + RUN + 3.1416 + + + CALL TURBO ON en CALL TURBO OFF mogen niet genest worden. + Voorbeeld: + + 10 CALL TURBO ON + 20 I=1 + 30 IF I=1 THEN CALL TURBO OFF:GOTO 300 + 40 .. + 50 CALL TURBO OFF + .. + .. + 300 .. + + Als dit programma geRUNd wordt zal er een foutmelding + verschijnen. + + + V E R S N E L L E N + + Om de snelheid van uitvoer op te voeren kunt u het volgende + doen: + - Gebruik zoveel mogelijk integer variabelen. + - Voor grafisch werk zonder sprites: voeg dit in: + VDP(9)=VDP(9) OR 2. Dit schakelt het sprite-systeem uit, + zodat de VDP meer tijd over heeft om de andere zaken uit te + voeren. Dit kan juist het laatst beetje extra snelheid zijn + dat uw programma nodig heeft om "smooth" te zijn. Om het + sprite-systeem weer aan te schakelen: VDP(9)=VDP(9) AND 253. + + + N A D E L E N + + Een nadeel is dat het gecompileerde programma niet apart op + disk gezet kan worden, zoals MCBC wel kan. Een ander nadeel + is de vrij grote onnauwkeurigheid van de reals (dubbele + precisie variabelen). Voor het tekenen van fractals e.d. kan + met niet al te nauwkeurig de coordinaten ingeven. (Zie ook + deze disk). + + De lijst van niet te compileren opdrachten zie ik niet als + nadeel. Het zijn meestal de I/O opdrachten en de snelheid + van uitvoeren ligt dan vaak aan het apparaat zelf. + + De BC is (volgens mij) vooral geschikt voor grafisch werk in + BASIC. Je kunt er zelfs op een normale MSX2 een horizontale + smooth-scroll over het hele scherm in SCREEN 5 mee maken. + (zie vorige SRS, ALPHA.BAS) + + Ook de maximale grootte van het bron-programma is toch wel + beperkt. Op MSX2 en hoger valt dat enigzins op te vangen + door slim gebruik te maken van de memory-mapper, maar dan + zit je met de variabelen te kijken, die moeten dan in page 4 + of in het VRAM, wat de snelheid niet bevordert. + + Na, dat was het wel. Zijn er vragen over (KUN-)BASIC, + schrijf dan gerust naar de Sunrise postbus t.a.v. + ondergetekende. + + Tot de volgende keer, met (misschien) een + vector-graphics-maker in KUN. Programmeer ze! En je weet + het: programmeren in BASIC: moet KUNnen! + + Randy Simons diff --git a/sunrise_special/4/MBScan.md b/sunrise_special/4/MBScan.md new file mode 100644 index 0000000..54ab10e --- /dev/null +++ b/sunrise_special/4/MBScan.md @@ -0,0 +1,76 @@ + M B S C A N V O O R D O S 2 + + + Op de vorige Sunrise Magazine stond MBSCAN.BIN, een zeer + handig programmaatje om de gegevens van alle MoonBlaster + files op een enkel- of dubbelzijdige disk onder DOS1 te + bekijken. + + Alle met MoonBlaster gemaakte muziekdisks kunnen daarmee + worden bekeken. MB werkt immers alleen met enkel- of + dubbelzijdige diskettes onder DOS1. + + + H D + + Nu zijn er echter van die irritante HD gebruikers die overal + een HD versie van willen hebben, en dus ook van MBSCAN + (Nvdr. Hmmfff...). Waar ze dat voor willen gebruiken is mij + een raadsel, want een offici�le HD versie van MoonBlaster + bestaat niet en voor mensen die MoonBlaster niet hebben en + de muziekjes alleen maar afspelen heeft het weinig nut, want + wie verspreid er nou EDIT versies van muziekjes? + + Enfin, voor de HD gebruikers die een directory met MB + muziekjes hebben en deze toch met MBSCAN willen bekijken, + heb ik samen met Kasper (juist ja, ook zo'n HD freak) MBSCAN + omgebouwd tot een DOS2 versie. + + + W E R K I N G + + De werking is vrij simpel: + + MBSCAN [drive:][directory] + + Wordt er niets ingevuld, dan wordt de huidige directory + genomen. Van elke .MBM file wordt de naam gegeven, EDIT of + USER, de titel en de drumkit. De uitvoer kan worden + gepauzeerd met de spatiebalk en met ^C kan het programma + voortijdig worden be�indigd. + + + R E D I R E C T I O N I N G + + De schermuitvoer werkt via de BDOS, wat als voordeel heeft + dat de redirectioning kan worden gebruikt. Dat is erg handig + en meteen ook de enige zinnige functie van MBSCAN.COM die ik + kan bedenken voor mensen die geen HD hebben, je kunt zo heel + eenvoudig een overzicht van alle muziekjes naar een file of + naar de printer sturen. Bijvoorbeeld: + + MBSCAN A:\MB>H:MUSIC.TXT + + Zet de info van alle muziekjes in de directory \MB op drive + A: in de file MUSIC.TXT op drive H:. Het is in verband met + de snelheid zeer raadzaam om de tekstfile op H: te laten + komen. Nog een voorbeeld: + + MBSCAN>PRN + + Print de info van de muziekjes in de huidige directory uit. + + + T E N S L O T T E + + Heb je geen HD maar wel DOS2, blijf dan gewoon MBSCAN.BIN + gebruiken. Ik neem niet aan dat je de muziekjes in + directory's hebt gezet, en MBSCAN.BIN is nu eenmaal sneller + dan MBSCAN.COM, omdat er rechtstreeks sectoren worden + gelezen. + + Voor de HD gebruikers is er nu dus MBSCAN.COM, zet voor een + optimale snelheid op de turbo R de BUFFERS op maximaal. Veel + plezier! + + Stefan Boer diff --git a/sunrise_special/4/MSX Audio.md b/sunrise_special/4/MSX Audio.md new file mode 100644 index 0000000..1c93d54 --- /dev/null +++ b/sunrise_special/4/MSX Audio.md @@ -0,0 +1,95 @@ + M S X A U D I O + + + Ik heb dit programma geschreven om de Music Module te + gebruiken bij Compile spellen die op HD staan (en niet naar + BASIC te hoeven). De syntax is: + + MSXAUDIO [ON|OFF] + + Bij ON wordt de MSX-AUDIO chip goed gezet zodat Compile + spellen hem herkennen. Het kan zijn dat bepaalde programma's + hierdoor blijven hangen. De EXTBIO hook wordt nl. gewoon + aangepast ("POKE -54,35"). Indien iemand weet hoe het wel + volgens de standaard kan, of in het bezit is van een �chte + MSX-AUDIO cartridge: laat het even weten. Ik ben dus + ge�nteresseerd in de waarden die op adres #ffca t/m #ffce + staan. + + + D E S O U R C E + + BDOS: EQU 5 + FCB1: EQU #5c + + in a,(#c0) + inc a ;c hoog -> a was 255 + ; -> geen AUDIO + jr c,NoAUDIO + + Als op poort #c0 de waarde 255 staat, is er geen MSX-AUDIO + aanwezig. + + ld hl,#ffca + ld a,(FCB1+2) + cp "F" + jr z,Off + cp "f" + jr nz,On + + FCB1 bevat de tekst die achter de COM file wordt meegegeven, + maar dan wel in zo'n vorm dat je er meteen een FCB mee kunt + openen. Ik check alleen of er een "F" staat op het tweede + karakter van de filenaam. Alles behalve dit betekent dat + MSX-AUDIO aan wordt gezet. + + + Off: ld a,i + ld (hl),a + ld de,tOff + jr Print + + Om hem ook uit te kunnen zetten heb ik iets gedaan wat + eigenlijk niet mag. Ik heb register I ervoor gebruikt. Voor + zover ik weet wordt het niet door andere programma's + veranderd, en is (was...) het dus een uitstekende plaats om + iets in te zetten dat even bewaard moet blijven. + + + On: ld a,(hl) + ld i,a + ld a,35 ;? + ld (hl),a + ld de,tOn + jr Print + + Ik weet niet precies waarom er 35 op #ffca moet komen, want + de mnemonics die dan aan die hook hangen slaan nergens op. + Vandaar ook dat de computer blijft hangen als er andere + programma's gerund worden die die hook gebruiken. Bijv. TED. + Dat is tevens de reden dat ik een off-optie heb gemaakt. + + + NoAUDIO: ld de,tNoAUDIO + Print: ld c,9 + jp BDOS + + tOn: db "Your non-standard MSX-AUDIO chip " + db "can now be used as a " + db "standard Panasonic",13,10 + db "MSX-AUDIO module.",13,10,"$" + + tOff: db "EXTBIO hook is restored.",13,10,"$" + + tNoAUDIO: db "No MSX-AUDIO chip available.",13,10 + db "$" + + + N O O T + + Ik weet ook wel dat het niet klopt allemaal, en dat het + eigenlijk niet mag volgens de standaard. Maar het programma + is handig wanneer je je Music Module wilt gebruiken bij + spellen van Compile op HD. + + Kasper Souren diff --git a/sunrise_special/4/NTM Coordin.md b/sunrise_special/4/NTM Coordin.md new file mode 100644 index 0000000..08638c2 --- /dev/null +++ b/sunrise_special/4/NTM Coordin.md @@ -0,0 +1,204 @@ + N T M C O O R D I N + + + G E B R U I K + + Deze TSR was een ideetje van CTS, en ik heb hem gemaakt. Je + kunt zo heel simpel in BASIC bepalen op welke coordinaat de + cursor staat. Deze coordinaten worden nl. op F1 en F2 gezet. + + Als je ESC inhoudt, blijven de waarden onder F1 en F2 + ongewijzigd. Je kunt zo makkelijk de coordinaten in een + BASIC-programma gebruiken. + + Onder TED levert deze TSR problemen op, omdat nu gewoon de + x- of y-coordinaat op het scherm komt als je op F1 of F2 + duwt. + + Bij het verwijderen worden de oude functietoets-instellingen + weer hersteld. + + + B E S P R E K I N G S O U R C E + + Ik zal alleen de gedeelten bespreken die specifiek voor + Coordin zijn. + + Hook EQU #FDA9 ;H.DSPC: aan begin van + ;routine die cursor + ;zichtbaar maakt + + Bij het zoeken naar een geschikte hoek vond ik H.DSPC. Als + je de routine aan de interrupt hangt, wordt de routine veel + te vaak uitgevoerd. Dat heeft dus geen nut(h). Bij deze hook + wordt de routine alleen uitgevoerd als hij nodig is. + Namelijk vlak voordat de cursor op het scherm wordt gezet. + + + X_coor: EQU #F3DD + Y_coor: EQU #F3DC + FNKST: EQU #F87F + DSPFNK: EQU #00CF + + Dit zijn de benodigde adressen. X_coor en Y_coor zijn gewoon + de coordinaten van de cursor. FNKST is het adres waar de + data van de functietoetsen staat. Met DSPFNK kun je de + functietoetsen aan zetten. + + + Kill: LD HL,Buffer + LD DE,FNKST + LD BC,32 + LDIR + + LD A,(#F3DE) ;F-keys aan? + OR A + JP NZ,DispKeys + RET + + Kopieer eerst de data naar een buffer om de functietoetsen + te herstellen na verwijderen van de TSR. Als de + functietoetsen aan staan, wordt de herstelde tekst ook weer + op het scherm gezet. Dit met de routine DispKeys. + + + Program: PUSH AF + PUSH BC + PUSH DE + PUSH HL + + Ik weet niet welke registers wel of niet veranderd mogen + worden, maar dit is het veiligst. + + + DI + IN A,(#AA) + AND 240 + OR 7 + OUT (#AA),A + IN A,(#A9) + EI + AND %100 + JR Z,Quit + + Leest rij 7 van het toetsenbord. AND 240 is om de high + nibble niet aan te passen. OR 7 zorgt dat rij 7 wordt gezet. + ESC is de derde toets in de rij, dus AND %100. Als ESC is + ingedrukt wordt de routine be�indigd. De functietoetsen + mogen dan niet worden aangepast. + + + LD A,(X_coor) + LD HL,FNKST + CALL HexDec + + A is waarde van toets en HexDec zet die als ASCII op adres + FNKST. + + LD A,(Y_coor) + LD HL,FNKST+16 + CALL HexDec + + Idem. + + LD A,(#F3DE) ;F-keys aan? + OR A + CALL NZ,DSPFNK + + Als functietoetsen aan staan, wordt de tekst ook op het + scherm gezet. + + + Quit: POP HL + POP DE + POP BC + POP AF + RET + + Registers weer herstellen en terugspringen naar de TSR + handler. + + + HexDec: DEC A ;E�n verminderen, + ;coordinaten van LOCATE + ;werken anders dan de + ;coordinaten op #F3DC en + ;#F3DD + LD E,0 ;Zet E op nul + + HD2: SUB 10 ;10-tal in E + INC E + JR NC,HD2 + + Trek telkens 10 af van A, en tel telkens 1 op bij E, totdat + A kleiner dan 0 is. + + ADD A,10 + DEC E + + Dan wordt E 1 verminderd en 10 opgeteld bij A. Dit stukje + (vanaf HD2) is eigenlijk E=A MOD 10, A=A DIV 10 (of in + BASIC: A=A \ 10). + + LD B,A ;1-heid in B + + P10: LD A,E + OR A + JR Z,P1 + ADD A,"0" + LD (HL),A + INC HL + + Maak even een ASCII waarde van E en B. Als E nul is, wordt B + opgeschoven. Daarom wordt INC HL alleen gedaan als E niet 0 + is. (Oftewel, bij de waarde 10 in A krijg je "10" en bij 9 + krijg je niet niet "09" maar "9".) + + P1: LD A,B + ADD A,"0" + LD (HL),A + INC HL + LD (HL),0 + RET + + Zet de waarden nog even op de juiste plaats. + + + Buffer: DS 32 ;Voor de oude waarden van de + ;functietoetsen + + + Nog even een stukje van de Init routine: + + LD HL,FNKST + LD DE,Buffer + LD B,32 + Loop: LD A,(HL) + LD (DE),A + LD (HL),0 + INC HL + INC DE + DJNZ Loop + + Dit kopieert 32 bytes van de functietoetsenbuffer naar een + eigen buffertje; om de functietoetsen te herstellen bij het + verwijderen. Ik gebruik hier niet LDIR omdat ik ook de + functietoetsen wil wissen: LD (HL),0. + + LD A,(#F3DE) ;F-keys aan? + OR A + JR NZ,DispKeys + + XOR A + RET + + DispKeys: LD IY,(#FCC0) + LD IX,DSPFNK + CALL #001C + + Het is wel waarschijnlijk dat de BIOS aan staat, maar ik ga + er niet vanuit. Dit is een stuk zekerder dan gewoon CALL + DSPFNK. + + Kasper Souren + \ No newline at end of file diff --git a/sunrise_special/4/PCM Rechtstreeks.md b/sunrise_special/4/PCM Rechtstreeks.md new file mode 100644 index 0000000..4da5d47 --- /dev/null +++ b/sunrise_special/4/PCM Rechtstreeks.md @@ -0,0 +1,346 @@ + P C M R E C H T S T R E E K S + + + We hebben op vorige Specials al aandacht besteed aan het + aansturen van de PCM chip in de turbo R door middel van de + BIOS calls PCMPLY en PCMREC. De PCM chip kan echter ook + rechtstreeks met OUT poorten worden aangestuurd. In dit + artikel ga ik het hier over hebben, en zal ik tevens de + sources geven van de standaard opneem- en afspeelroutines. + De maximale opneemfrequentie is zo'n 25 kHz! Het afspelen + kan zelfs nog sneller, maar dat heeft dus alleen zin voor + samples die op een andere computer zijn opgenomen. + + + I / O P O O R T E N + + Voor de PCM chip zijn twee I/O poorten gereserveerd: &HA4 en + &HA5. De indeling van deze poorten is als volgt: + + MSB 7 6 5 4 3 2 1 0 LSB + + &HA5 write 0 0 0 SMPL SEL FILT MUTE ADDA + &HA5 read COMP 0 0 SMPL SEL FILT MUTE BUFF + &HA4 write DA7 DA6 DA5 DA4 DA3 DA2 DA1 DA0 + &HA4 read 0 0 0 0 0 0 CT1 C10 + + De beschikbare uitleg van deze bits is slechts zeer beknopt, + waardoor ik zelf ook niet van alle bits de exacte werking + weet. Ik geef hieronder de letterlijke tekst die ik heb. Als + je gewoon de standaardroutines gebruikt heb je het niet + nodig, maar ik geef de tekst toch maar voor het geval er + mensen zijn die er wel iets aan hebben. + + + ADDA (BUFF): Buffermode + Bepaalt de uitvoer van de D/A converter. Zet hem in geval + van D/A conversie (dubbele buffer) op 0, en in geval van A/D + conversie op 1. Verder, komt hij bij een reset op dubbele + buffer te staan (default). + + MUTE: Muting-besturing + Zet de geluidsuitvoer aan of uit. + 0: geen uitvoer (default) + 1: wel uitvoer + + N.B. Bij afspelen moet dit uiteraard altijd op 1 worden + gezet, anders hoor je niets. Als je het op 1 zet bij + opnemen, hoor je het geluid dat wordt opgenomen tegelijker- + tijd uit de luidspreker komen. + + FILT: Keuze van het invoersignaal van het + samplehold-circuit + Bepaalt, in het geval van A/D conversie, of het signaal dat + men in het samplehold-circuit invoert een signaal moet zijn + dat door een filter afgegeven wordt of een standaard signaal + moet zijn. Door 0 te kiezen wordt het een geluid van een + standaard signaal, en door 1 te kiezen wordt het een geluid + van een filter-uitgangssignaal. De default waarde is 0. + + SEL: keuze van het filter-inganssignaal + Bepaalt of het signaal dat men in het low-pass filter + invoert een signaal moet zijn dat door de D/A converter + afgegeven wordt, of dat het een signaal moet zijn dat door + de microfoonversterker wordt afgegeven. Met keuze 0: geluid + afgegeven door de D/A converter, en door 1 te kiezen, kiest + men voor geluid dat door de microfoonversterker wordt + afgegeven. + + SMPL: Samplehold-signaal + Bepaalt of het ingangssignaal gesampled of geHOLD dient te + worden. + 0: Samplen (default) + 1: HOLDen + + COMP: Uitgangssignaal van de comparator + Vergelijkt het uitgangssignaal van de samplehold en dat van + de D/A converter. + 0: D/A uitvoer groter dan samplehold uitvoer + 1: D/A uitvoer kleiner dan samplehold uitvoer + + DA7 tot DA0: D/A uitvoer data + Wanneer men PCM data afspeelt, kan met het PCm geluid + afspelen door de gebruikte data hier naartoe uit te voeren. + Het formaat van de data is absoluut binair, en 127 komt + overeen met level 0. + + CT1 en CT0: counter data + Bij elke 63.5 microseconde wordt deze waarde verhoogd. De + data die op adres &HA4 werd geschreven tegelijk met het + ophogen op het moment van een D/A conversie wordt gekopieerd + en uitgevoerd. Wanneer men op adres &HA4 schrijft, wordt de + counter gewist. + + N.B. Deze counter wordt door de BIOS routines gebruikt voor + de vier opneem- en afspeelsnelheden die daar beschikbaar + zijn. + + + A F S P E L E N + + Wie het bovenste goed heeft gelezen, heeft waarschijnlijk al + gezien dat het afspelen heel makkelijk is. Gewoon de data + naar &HA4 sturen. Met de counter van de sampler zijn maar + vier snelheden mogelijk (15.75, 7.875, 5.25 en 3.94 kHz), + maar door de systeemcounter van de turbo R (zie SRS#3) te + gebruiken, kunnen we de snelheid veel nauwkeuriger opgeven. + De PCM playroutine ziet er als volgt uit: + + ; P C M . A S C + ; Play/record routines voor turbo R PCM + ; Standaardroutines van ASCII + + ; Sunrise Special #4 + ; (c) Stichting Sunrise 1993 + + PMDAC: EQU &HA4 ; write + PMCNT: EQU &HA4 ; read + PMCNTL: EQU &HA5 ; write + PMSTAT: EQU &HA5 ; read + SYSTML: EQU &HE6 ; 3.911 us system counter + + ; Play + ; R800 only! + ; In: HL beginadres + ; BC lengte + ; E snelheid + + PLAY: LD A,&B00000011 + OUT (PMCNTL),A ; D/A mode + DI + XOR A + OUT (SYSTML),A ; reset counter + + PLAY1: IN A,(SYSTML) + CP E + JR C,PLAY1 + XOR A + OUT (SYSTML),A + + LD A,(HL) ; PCM data + OUT (PMDAC),A + INC HL + DEC BC + LD A,C + OR B + JR NZ,PLAY1 + EI + RET + + Eerst worden MUTE en ADDA op 1 gezet en SMPL, SEL en FILT op + 0. Daarna wordt de PCM data naar &HA4 gestuurd, waarbij de + systeemcounter op &HE6 wordt gebruikt voor de timing. Zoals + u ziet, zeer eenvoudig. Het opnemen gaat helaas een stuk + moeizamer, omdat we dat per bit moeten doen! + + + O P N E M E N + + Hier volgt eerst maar de source: + + ; Record + ; R800 only! + ; In: HL adres + ; BC lengte + ; E snelheid + + REC: LD A,&B00001100 + OUT (PMCNTL),A ; A/D mode + DI + XOR A + OUT (SYSTML),A ; reset counter + + REC1: IN A,(SYSTML) + CP E + JR C,REC1 + XOR A + OUT (SYSTML),A + + PUSH BC + LD A,&B00011100 + OUT (PMCNTL),A ; data hold + LD C,PMSTAT + + LD A,&B10000000 ; bit 7 + OUT (PMDAC),A ; bit convert + DB &HED,&H70 ; IN F,(C) + JP M,RECAD0 + RES 7,A + + RECAD0: SET 6,A ; bit 6 + OUT (PMDAC),A + DB &HED,&H70 + JP M,RECAD1 + RES 6,A + + RECAD1: SET 5,A ; bit 5 + OUT (PMDAC),A + DB &HED,&H70 + JP M,RECAD2 + RES 5,A + + RECAD2: SET 4,A ; bit 4 + OUT (PMDAC),A + DB &HED,&H70 + JP M,RECAD3 + RES 4,A + + RECAD3: SET 3,A ; bit 3 + OUT (PMDAC),A + DB &HED,&H70 + JP M,RECAD4 + RES 3,A + + RECAD4: SET 2,A ; bit 2 + OUT (PMDAC),A + DB &HED,&H70 + JP M,RECAD5 + RES 2,A + + RECAD5: SET 1,A ; bit 1 + OUT (PMDAC),A + DB &HED,&H70 + JP M,RECAD6 + RES 1,A + + RECAD6: SET 0,A ; bit 0 + OUT (PMDAC),A + DB &HED,&H70 + JP M,RECAD7 + RES 0,A + + RECAD7: LD (HL),A ; PCM data + LD A,&B00001100 + OUT (PMCNTL),A + POP BC + INC HL + DEC BC + LD A,C + OR B + JR NZ,REC1 + + LD A,&B00000011 + OUT (PMCNTL),A ; D/A mode + EI + RET + + Eerst worden SEL en FILT op 1 gezet en MUTE, HOLD en ADDA op + 0. De systeemcounter op &HE6 wordt net als bij de play + routine gebruikt voor de timing. Nu wordt ook de HOLD op 1 + gezet en wordt de waarde &H80 naar &HA4 geschreven. De PCM + chip zal nu het COMP bit zetten als het signaal sterker is + dan &H80, en het wissen als het signaal minder sterk is. + COMP wordt gelezen door met IN F,(C) register &HA5 in het F + register te lezen, waarbij bit 7 (COMP) dus de sign vlag + wordt. + + Is het signaal sterker dan &H80, dan blijft de waarde van A + ongewijzigd, was het zwakker, dan wordt bit 7 gewist. Nu + wordt bit 6 gezet. Weer wordt deze waarde naar &HA4 + geschreven om hem te vergelijken, en ook weer wordt COMP + uitgelezen via het sign bit van het vlagregister. Is het + signaal sterker, dan blijft bit 6 gezet, is het zwakker, dan + wordt bit 6 gereset. Zo wordt bit voor bit een byte PCM data + samengesteld. + + + M A X I M A L E F R E Q U E N T I E + + Deze routine is behoorlijk lang, en dat beperkt dan ook de + maximale frequentie waarmee kan worden opgenomen. Ik heb het + getest en het blijkt dat het E register een waarde moet + hebben van minimaal 10. Geeft u een lagere waarde op, dan + zal dat toch dezelfde snelheid als bij 10 worden. + + Hieronder een overzicht van een aantal mogelijke waardes van + E en de bijbehorende frequentie in kHz: + + 10 25.568 kHz + 11 23.244 kHz + 12 21.307 kHz + 13 19.668 kHz + 14 18.263 kHz + 15 17.045 kHz + 16 15.980 kHz + 17 15.040 kHz + 18 14.205 kHz + 19 13.457 kHz + 20 12.784 kHz + 21 12.175 kHz + 22 11.622 kHz + 23 11.117 kHz + 24 10.653 kHz + 25 10.227 kHz + 26 9.834 kHz + 27 9.470 kHz + 28 9.131 kHz + 29 8.817 kHz + 30 8.523 kHz + 31 8.248 kHz + 32 7.990 kHz + 33 7.748 kHz + 34 7.520 kHz + 35 7.305 kHz + 36 7.102 kHz + 37 6.910 kHz + 38 6.728 kHz + 39 6.556 kHz + 40 6.392 kHz + 41 6.236 kHz + 42 6.088 kHz + 43 5.946 kHz + 44 5.811 kHz + 45 5.682 kHz + 46 5.558 kHz + 47 5.440 kHz + 48 5.327 kHz + 49 5.218 kHz + 50 5.114 kHz + + Zoals u ziet is de maximale opneemfrequentie maar liefst + 25.568 kHz! Dat is heel wat meer dan de 15.75 kHz die met de + BIOS routines kan worden gehaald. Het afspelen kan + natuurlijk nog sneller, maar dat heeft alleen zin voor + samples die op een andere computer zijn opgenomen. + + De source PCM.ASC is op de diskette aanwezig. + + + G E I N T J E + + Een leuk geintje is tenslotte nog om de geluidstoevoer van + de turbo R aan te zetten. Pas daarbij wel op dat het geluid + niet kan gaan zingen tussen de microfoon en de luidspreker, + want dat geeft een ontzettende rotherrie. Vooral met de + ingebouwde microfoon gebeurt dat snel. Het is heel simpel, + gewoon in BASIC intypen: + + OUT &HA5,10 + + De doorvoer kan uiteraard ook weer uit, daarvoor typt u: + + OUT &HA5,8 + + Natuurlijk kunt u dit ook in ML programmeren... + + Stefan Boer diff --git a/sunrise_special/4/Print routine.md b/sunrise_special/4/Print routine.md new file mode 100644 index 0000000..ae6a44b --- /dev/null +++ b/sunrise_special/4/Print routine.md @@ -0,0 +1,203 @@ + P R I N T R O U T I N E + + + Met de hier volgende printroutine wordt een tekst op alle + breedten goed op het scherm gezet, voor zover dat mogelijk + is. + + + BDOS: EQU #0005 + + ;BDOS functie + StrOut: EQU 9 + + LINLEN: EQU #f3b0 ;Aantal tekens op + ;huidige scherm + + + call Print + db 2,2 ;Kantlijnen + + db "PRINTROUTINE",1 + db "============",1 + db 1 + db "Dit is een test voor mijn " + db "printroutine. " + db "Hopelijk werkt het goed.",1 + db 1 + db "De bedoeling is dat de " + db "tekst door de routine zelf goed " + db "op het scherm gezet wordt, " + db "ongeacht schermbreedte. " + db "Nu nog automatisch afbreken :-)",1 + db 1 + db "Hier begint een nieuwe alinea!",0 + rst 0 + + De routine wordt aangeroepen met de tekst achter de call. + Zo weet je precies wat er op het scherm komt te staan, en + hoef je niet met labels te werken. Om aan te geven dat een + nieuwe regel begint moet een 1 worden gebruikt, en de 0 + geeft het einde van de tekst aan. + + + ;P R I N T + ;Doel : Zet tekst op scherm + ;Input : hl: pointer naar tekst + ;Output: carry hoog: kantlijnen te groot + ;Noot : eerste 2 bytes van de tekst zijn respectievelijk + ; de rechter- en linkerkantlijn + + + Print: ex (sp),hl + + Dit zorgt ervoor dat de tekst achter de call kan staan. + + + ld a,(LINLEN) + dec a + sub (hl) + jr c,pError + + Rechterkantlijn van breedte aftrekken. Als het resultaat + kleiner dan 0 is, wordt teruggesprongen met de carry hoog. + + inc hl + sub (hl) + jr c,pError + ld (pLength),a + ld a,(hl) + inc hl + + Vervolgens wordt hetzelfde met de linkerkantlijn gedaan. De + linkerkantlijn is nog nodig om te bepalen vanaf waar de + buffer (83 tekens) moet worden beschreven. + + + push hl + ld hl,pBuffer1 + ld d,0 + ld e,a + add hl,de ;Tel linkerkantlijn + ;op bij buffer + ld (pAddress3),hl + pop hl + + pLoop1: ld a,(pLength) + ld b,a + ld de,(pAddress3) + pLoop2: ld a,(hl) + cp " " ;Spatie? + call z,pSpace + cp 1 ;Einde alinea? + jr z,pAlinea + or a ;Einde tekst? + jr z,pQuit + + Bij een spatie worden de adressen bewaard. Bij een 0 wordt + niet zomaar geRETurnd, want hl moet weer verwisseld worden + met het returnadres (dit i.v.m. tekst achter call). + + + ld (de),a + inc hl + inc de + djnz pLoop2 + + cp " " + jr z,sPrint2 + + Als het laatste teken een spatie is, hoeft er niet terug + worden gegaan naar de vorige spatie. + + + ld a,(pFlag) + or a + jr z,sPrint2 + + Als er nog geen spatie in de regel zit (pFlag wordt door de + routine pSpace gezet), kan er niet worden gekeken naar de + vorige spatie in de regel. In dit geval is de schermbreedte + te klein, en komt de tekst niet goed op het scherm. + + + xor a + ld (pFlag),a + ld hl,(pAddress1) + ld de,(pAddress2) + inc hl + sPrint2: call sPrint1 + jr pLoop1 + + pSpace: ld (pAddress1),hl + ld (pAddress2),de + ld (pFlag),a + ret + + Adressen van spatie bewaren en vlag zetten. + + + pQuit: call sPrint1 + xor a ;Carry laag + ex (sp),hl + ret + + Carry laag, want carry hoog bij terugkeer betekent een + error. + + + pAlinea: call sPrint1 + inc hl + jr pLoop1 + + Bij een nieuwe alinea moet de 1 worden overgeslagen. + + + sPrint1: push hl + ld a,13 + ld (de),a + inc de + ld a,10 + ld (de),a + inc de + ld a,"$" + ld (de),a + + Zet waarden voor einde van regel en einde van string op de + juiste adressen. + + ld de,pBuffer1 + ld c,StrOut + call BDOS + pop hl + ret + + pError: xor a ;Zoeken naar 0 + ld bc,-1 + cpir + ex (sp),hl + scf + ret + + bc wordt op -1 gezet om het hele geheugen te doorzoeken + naar de 0. scf is nog om de carry weer hoog te zetten. cpir + zet de carry namelijk weer laag. + + + ;Data + + pBuffer1: ds 79+3," " ;Buffer voor regel + pAddress1: dw pBuffer1 + pAddress2: dw 0 + pAddress3: dw pBuffer1 ;Buffer + + ;linkerkantlijn + pFlag: db 0 ;Vlag voor spatie + ;in regel + pLength: db 80 + + + De buffer is 79+3 omdat een regel in principe 80-1 + karakters lang kan zijn, en 3 bytes nodig zijn om return en + het einde van de string aan te duiden. + + Kasper Souren diff --git a/sunrise_special/4/R800 Drive.md b/sunrise_special/4/R800 Drive.md new file mode 100644 index 0000000..f3fedbd --- /dev/null +++ b/sunrise_special/4/R800 Drive.md @@ -0,0 +1,34 @@ + R 8 0 0 D R I V E + + + Dit programma van XelaSoft heeft ongeveer hetzelfde effect + als mijn Fastdrive, die op Sunrise Magazine #6 stond. Alleen + kun je met R800 drive nog bepalen bij welke drives wordt + teruggeschakeld. + + + L E D 'J E + + Het programma werkte eerste niet op mijn FS-A1ST, maar ik + heb dat even aangepast. Ook heb ik het zo gemaakt, dat je + ook kunt zien wanneer de Z80 mode wordt aangeschakeld. Dat + geeft mij een veiliger gevoel (nee, het is niet + vergelijkbaar met OB). + + + T E R U G S C H A K E L E N + + Het terugschakelen moet gebeuren bij de gewone diskdrive �n, + als je een MAK interface hebt, bij de harddisk. De MK en HSH + SCSI interfaces kunnen de snelheid van de R800 wel gewoon + aan. + + Het enige nadeel van dit programma t.o.v. mijn Fastdrive is + dat het vanuit BASIC moet worden opgestart. Dat komt omdat + het een stuk geheugen moet reserveren. + + De source staat ook op disk, dit om te laten zien hoe je + TSR's onder MSX-DOS 2 kunt maken, zonder MemMan te + gebruiken. + + Kasper Souren diff --git a/sunrise_special/4/Random.md b/sunrise_special/4/Random.md new file mode 100644 index 0000000..1f74823 --- /dev/null +++ b/sunrise_special/4/Random.md @@ -0,0 +1,181 @@ + R A N D O M + + + In MCCM 58 stond deze source. Deze was echter zonder het + -TIME gedeelte. Zonder eerst RND(-TIME) te doen krijg je + geen goede random. Het begint dan telkens hetzelfde. Verder + was vergeten de DAC op integer te zetten. + + De Math-pack routines zitten helaas niet alleen in de MSX1 + BIOS. Ze zitten deels in de BASIC ROM, en dus dien je die in + te schakelen bij gebruik. Je moet dus even opletten met + terugschakelen indien je page 1 nog nodig hebt. En zorgen + dat je geen data op page 1 gebruikt. + + + W B A S S 2 V S . G E N 8 0 + + Ikzelf gebruik GEN80, maar ik heb ook maar even een WBASS2 + source op disk gezet. Misschien dat ik GEN80 maar eens moet + bespreken vanuit mijn oogpunt, want ik herinner me nog dat + op Sunrise Special #1 stond dat WBASS2 "beter" is. + + + B I O S A A N R O E P + + De math-pack aanroepadressen zitten in de BIOS. Daarom even + een macrootje. + + BIOS: MACRO @Address + ld iy,(#fcc0) + ld ix,@Address + call #001c + ENDM + + + Start: ld h,#40 ;Page 1 + ld a,(#fcc1) ;BIOS slot + call #0024 ;ENASLT + + Om te beginnen wordt de BASIC ROM op page 1 gezet. De + aanroepadressen zitten dan wel in de BIOS, maar je moet toch + zorgen dat de BASIC ROM op page 1 staat. + + + ld de,0 ;Benedengrens + ld hl,#1000 ;Bovengrens + call Random + call PrintHL + + Dit behoort duidelijk te zijn. + + + ld h,#40 + ld a,(#f342) ;RAM voor page 1 + call #0024 + rst 0 + + Even page 1 terugzetten, ik weet niet of het ook goed zonder + dit, maar dit is altijd een stuk netter. + + + ;PrintHL + ;Doel : zet hl op scherm + ;In : hl + ;Verandert: alles + + PrintHL: ld a,h ;eerst high byte + push hl ;hl bewaren + call PrintA ;print a + pop hl + ld a,l ;dan low byte + PrintA: push af ;af bewaren + and %11110000 ;high nibble + rrca ;verplaatsen naar + rrca ;low nibble + rrca + rrca + call PrintNibble ;nibble printen + pop af + and %1111 ;low nibble + PrintNibble: cp 10 ;ook A t/m F + jr c,NoHex ;goed printen + add a,"A"-"0"-10 + NoHex: add a,"0" + BIOS #a2 ;print karakter + ret + + Dit is een handige manier om hl op het scherm te zetten. De + routine bevat ook meteen routines om a of de low nibble van + a op het scherm te zetten. + + + ;Random + ;Doel : genereert een random-getal tussen bepaalde + ; grenzen + ;In : hl=bovengrens, de=benedengrens + ;Uit : hl=random getal + ;Verandert: alles + ;Noot : op page 1 moet de BASIC ROM staan + + ;Math-pack entry's + FRCINT: EQU #2f8a ;DAC -> integer + ;[op (DAC+2)] + FRCDBL: EQU #303a ;DAC -> dubbele + ;precisie + RND: EQU #2bdf ;DAC = RND (DAC) + DECMUL: EQU #27e6 ;DAC = DAC * ARG + + ;Data voor Math-pack + DAC: EQU #f7f6 + ARG: EQU #f847 + VALTYP: EQU #f663 + + JIFFY: EQU #fc9e ;TIME in BASIC + + De gebruikte adressen. + + + Random: ld a,2 ;DAC is integer + ld (VALTYP),a + ld (Offset),de ;Bewaar ondergrens + or a ;Carry laag + sbc hl,de ;Bereken vermenig- + ;vuldigingsfactor + ld (Multiply),hl + + ld a,(FlagRnd) ;Routine al + ;aangeroepen? + or a + jr z,RndFirst + + Als Random de eerste keer wordt aangeroepen wordt niet + RND(1) maar RND(-TIME) gedaan. Hierdoor krijg je echte + random, voor zover dat mogelijk is. + + + ld hl,1 ;Neem RND(1) + + RndContinue: ld (DAC+2),hl + BIOS RND + ld hl,DAC ;Verplaats DAC naar + ;ARG + ld de,ARG + ld bc,8 + ldir + ld hl,(Multiply) ;Vermenigvul- + ;digingsfactor => + ;dubbele precisie + ld (DAC+2),hl + ld a,2 ;Is nu nog een + ;integer + ld (VALTYP),a + BIOS FRCDBL + BIOS DECMUL + BIOS FRCINT + ld hl,(DAC+2) ;Offset erbij + ;optellen + ld de,(Offset) + add hl,de + ret + + RndFirst: ld a,255 ;Zet flag + ld (FlagRnd),a + ld hl,(JIFFY) ;hl=TIME + ex de,hl ;hl=-hl + ld hl,0 ;-) Dit kan vast op + or a ; een betere manier, + sbc hl,de ; maar ik heb nu + ; geen zin (tis + ; 2:28u) + jr RndContinue + + + Multiply: dw 0 + Offset: dw 0 + FlagRnd: db 0 ;Wordt 255 na eerste + ;aanroep + + Einde: END + + Kasper Souren diff --git a/sunrise_special/4/Read to kana.md b/sunrise_special/4/Read to kana.md new file mode 100644 index 0000000..ca1d064 --- /dev/null +++ b/sunrise_special/4/Read to kana.md @@ -0,0 +1,20 @@ + R E A D T O K A N A + + + Dit programma is door Erik Maas geschreven om het Kanji + gedeelte van de DRAM toch nog nuttig te kunnen gebruiken (de + studenten Japans onder ons kunnen dus alvast op ESC + drukken). + + Het laadt een file die op #4000 moet komen te staan in over + de DRAM page van de Kanji. Erik noemt het de KANA page, maar + ja, het maakt niet veel uit hoe je het noemt, veel nut(h) + heeft deze page toch niet. + + Het kan echter wel handig zijn om KUN-BASIC, of andere + programma's die CALL's mogelijk maken, erin te zetten. + Misschien kan ook WBASS2 erin worden gezet, maar dit moeten + degenen die dit programma veelvuldig gebruiken zelf maar + uitzoeken. + + Kasper Souren diff --git a/sunrise_special/4/Tweede drive aan turbo r.md b/sunrise_special/4/Tweede drive aan turbo r.md new file mode 100644 index 0000000..1a37757 --- /dev/null +++ b/sunrise_special/4/Tweede drive aan turbo r.md @@ -0,0 +1,36 @@ + T W E E D E D R I V E A A N T U R B O R + + + Op de turbo R (FS-A1ST en FS-A1GT) zit normaal geen + drive-aansluiting. Met onderstaande gegevens is dat echter + simpel zelf te maken. + + + Printaan- 15 pens 34 pens + sluiting: sub-d: shugart: + + +5 volt : pen 1 pen 1 voedingsplug + Ground : pen 7 pen 2 voedingsplug + Ready : pen 6 pen 3 pen 34 + Side select : pen 9 pen 4 pen 32 + Read data : pen 11 pen 5 pen 30 + Write protected: pen 12 pen 6 pen 28 + Track 0 : pen 13 pen 7 pen 26 + Write gate : pen 14 pen 8 pen 24 + Write data : pen 16 pen 9 pen 22 + Step : pen 18 pen 10 pen 20 + Direction : pen 19 pen 11 pen 18 + Motor on : pen 20 pen 12 pen 16 + Drive select : pen 22 pen 13 pen 10 + Index : pen 23 pen 14 pen 8 + Disk change : pen 24 pen 15 pen 2 + + Drive instellen als DS0!! + + + D I S C L A I M E R + + Stichting Sunrise is NIET aansprakelijk voor eventuele + schade aan mens en/of machine door uitvoering van dit + project. + \ No newline at end of file diff --git a/sunrise_special/4/V9990 Specificaties.md b/sunrise_special/4/V9990 Specificaties.md new file mode 100644 index 0000000..199247a --- /dev/null +++ b/sunrise_special/4/V9990 Specificaties.md @@ -0,0 +1,128 @@ + V 9 9 9 0 S P E C I F I C A T I E S + + + P A T T E R N M O D E + + M O D E P 1 P 2 + ----------------------------------------------------------- + resolutie 32 x 26.5 64 x 26.5 + (256 x 212) (512 x 212) + aantal schermen 2 1 + karakter grootte 8 x 8 8 x 8 + aantal kleuren 15 + transp. 15 + transparant + palette 4 tabellen 4 tabellen + met 16 kleuren met 16 kleuren + uit 32768 uit 32768 + image space 64 x 64 128 x 64 + aantal patronen max. 16384 max. 16384 + + + S P R I T E S + + ------------------------------------------------------------ + grootte 16 x 16 + aantal sprites 125 op 1 scherm + 16 op 1 beeldlijn + aantal kleuren 15 + transparant voor elke pixel + elke sprite kan een eigen palette hebben + (1 van de 4!) + aantal patronen Je hebt 256 patronen, deze zou je volgens + het databoek ook samen kunnen laten vallen + met het "normale" scherm, om delen daarvan + als sprite te kunnen gebruiken; handig. + prioriteit Voor elke sprite kun je aangeven of deze + voor of achter het "normale" scherm moet + komen (kun je sprites ACHTER iets door laten + gaan i.p.v. er altijd voor laten hangen). + Als sprites elkaar overlappen, heeft het + laagste spritenummer voorrang. + ------------------------------------------------------------ + + + B I T M A P M O D E + + mode resolutie bits/dot + ------------------------------------------- + B1 256 x 212 16 + (256 x 424) 8 + 4 + 2 + B2 384 x 240 16 (256 kB nodig) + (384 x 480) 8 + 4 + 2 + B3 512 x 212 16 (256 kB nodig) + (512 x 424) 8 + 4 + 2 + B4 768 x 240 4 + (768 x 480) 2 + B5 640 x 400 4 (256 kB nodig) + 2 + B6 640 x 480 4 (256 kB nodig) + 2 + ------------------------------------------- + + In de eerste kolom staat de resolutie van het scherm, non + interlaced, en tussen haakjes de resolutie interlaced (er + zijn modes die niet interlaced kunnen worden weergegeven). + In de tweede kolom staat het aantal bit's wat er per pixel + (dot) gebruikt wordt. Ik vermeld niet het aantal kleuren, + want dat hangt af van welke mode (YJK, RGB of YUV) je + daarvoor gebruikt. + + Voorbeeld: 4 bits per dot is 2^4 = 16 kleuren, als je kiest + voor palette mode 0, betekent dat dat je 16 kleuren kunt + kiezen uit de 32768 mogelijke. + + Elk scherm is in feite een gedeelte van een Image, deze kan + groter zijn dan het scherm, bv. 2048 bij 1024 pixels. Wat + heb je daaraan, zul je denken, maar het is eigenlijk een + groot scherm, waarvan je een deel op je monitor plaatst. Je + kunt elk willekeurig gedeelte van de Image eruit lichten, + wat een omnidirectionele scroll geeft (zegt de handleiding + dus). Dit is niet alleen makkelijk voor spellen, maar ook + zeer handig voor DTP toepassingen. + + + P A L E T T E M O D E S + + bit/dot PLTM conversie methode aantal kleuren + ----------------------------------------------------------- + 16 0 RGB (!YS:1,G:5,R:5,B:5) 32768 + + 8 0 Palette 64 van de 32768 + 1 RGB (G:3, R:3, B:2) 256 + 2 YJK 19268 + 3 YUV 19268 + + 4 0 Palette 16 van de 32768 + + 2 0 Palette 4 van de 32768 + ----------------------------------------------------------- + + Je kunt bij elke display mode een palette mode kiezen, mits + het aantal bits per dot maar overeenkomen. Hieronder even de + uitleg van de tabel. + + Bit/dot : aantal bits dat er per pixel gebruikt wordt. + PLTM : manier van decoderen van kleuren, hoogste 2 bits + van register 13. + RGB : hierbij staat de RGB waarde in het geheugen, in de + tabel staat hoeveel bits er voor welke kleur wordt + gebruikt. (Bijv. SCREEN 8 bij de V9958.) + En dan nog een extra : het !YS bit, deze bepaalt + PER pixel of het bv. transparant is, en zo kan + worden gebruikt voor Super Impose. + Palette : in het geheugen staat een kleur nummer die zelf + een RGB waarde heeft, gekozen met het palette. + (Bijv. SCREEN 5.) + YJK : zelfde methode als SCREEN 12 + YUV : hiervan weet ik niet hoe het werkt, maar het zal + veel op YJK lijken + + Deze gegevens heb ik allemaal uit het V9990 aplication + manual. + + Erik Maas + \ No newline at end of file diff --git a/sunrise_special/4/V9990.md b/sunrise_special/4/V9990.md new file mode 100644 index 0000000..7606f28 --- /dev/null +++ b/sunrise_special/4/V9990.md @@ -0,0 +1,158 @@ + D E V 9 9 9 0 + + + Dit is een videochip, waar al veel geruchten over + rondgingen. Om maar meteen met de deur in huis te vallen, + deze VDP is NIET software compatible met de V9958 of de + V9938! (Dit in tegenstelling tot vele eerdere berichten.) + + + W A T K A N D A T D I N G ? + + Deze VDP kan in principe alles wat de V9958 ook kan. + De extra's: + + + D E S C H E R M E N + + Hogere resoluties, tot 768 x 480 interlaced en 640 x 480 non + interlaced. + + De textmode is verbeterd, nu heb je een schermmode + vergelijkbaar met SCREEN 2 en 4, maar de karakters kunnen + per pixel een kleur krijgen (niet meer afhankelijk van 2 + kleuren op een regel bij een karakter). + + Mogelijkheid om 2 schermen elkaar te laten overlappen, met + daarbij nog de mogelijkheid daarachter een superimpose + scherm te hebben. + + Een omnidirectionele scroll. Je beeld op je monitor is niet + je hele scherm, dit is slechts een gedeelte van je gehele + image, door middel van je scroll register kun je een + gedeelte van je image op het scherm projecteren. + + + D E K L E U R E N + + 32768 kleuren mogelijk op een scherm, zonder "colorspill", + waarbij ook nog per pixel kunt kiezen of deze transparant + is, voor superimpose. + + Bitmap mode met 64 kleuren uit een keuze van 32768, waarbij + je per kleur kunt kiezen of deze transparant is, voor + superimpose. + + Meer manieren om kleuren (scherminformatie) op te slaan in + het geheugen. YJK kennen we al van SCREEN 12, maar hier is + YUV bij gekomen, en van beiden zijn er dan weer varianten + van. + + + S P R I T E S + + Een hardware cursor, je kunt zelf je cursor tekenen, je hebt + 4 kleuren, waarvan er ��n transparant of een XOR kleur is. + + Verbeterde sprites, 125 ervan op een scherm, 16 op een + beeldlijn. En alsof het nog niet genoeg is, de sprites + kunnen nu per pixel een kleur krijgen, je kunt dus als je de + goede schermmode hebt, een sprite patroon gewoon uit het + "normale" scherm pakken. Deze sprites hebben bij hun + informatie ook nog een bit om te kiezen of ze voor of achter + de eerste scherm layer komen. Wel zijn de sprites nog steeds + "maar" 16 by 16 pixels. + + De sprites hebben 4 eigen pallettabellen, de kleuren van de + sprites zijn dus onafhankelijk van het "normale" scherm. + + + D I V E R S E N + + De VDP gaat nu zelf met de Kanji ROM om. Er zijn VDP + commando's om de VDP Kanji karakters op het scherm te laten + zetten. Je kunt gewoon aan de VDP doorgeven welke karakters, + en hij zet ze er wel neer. + + Teken commando's voor de VDP die ongeveer werken zoals de + DRAW commando's in MSX-BASIC (dX en dY, delta methode). + + VRAM read en VRAM write werken onafhankelijk van elkaar, kun + je terwijl de VDP een gedeelte van het scherm aan het + kopi�ren is, nog extra winst krijgen door zelf VRAM te + kopi�ren, zonder in RAM te hoeven bufferen. + + Deze VDP kan met verschillende schermen werken, bv. LCD, + RGB, TV. + + De VDP heeft de mogelijkheid tot digitaliseren en + superimpose. En kan hierbij werken met analoge en digitale + signalen. + + Je kunt je mode registers lezen, je kunt dus bijvoorbeeld + direct aan de VDP vragen wat hij voor schermmode op het + moment heeft, zonder deze registers in het RAM hoeven te + bewaren. Helaas gaat dit niet op voor de VRAM write/read + adressen, die zijn nog steeds write only. + + De I/O adressen zijn nog niet gespecificeerd, maar neemt wel + 16 adressen in beslag. + + Deze VDP is redelijk simpel op je MSX aan te sluiten, er + zijn weinig externe componenten nodig. Maar het is wel + mogelijk veel erop aan te sluiten, + + Het zou ook mogelijk moeten zijn om het VRAM direct aan te + spreken met de CPU, maar dat is nogal onduidelijk. + + + D E T E K O R T K O M I N G E N + + Deze VDP kan in textmode niet 80 tekens op een regel aan, + dus daar moet je een grafisch scherm voor pakken, wat op + zich niet zo erg is, door de snelheid van de VDP, en de + mogelijkheid om makkelijk karakters op het scherm te zetten + d.m.v. de Kanji ROM. + + Hij is niet PIN compatible met de V9938/58, maar dat is ook + niet zo vreemd, met al de extra mogelijkheden dat het ding + heeft. + + De prijs. Hij is vrij duur. + + + W A A R T E K O O P ? + + MSX Handlergemeinschaft heeft een kaart ontwikkeld, waar de + V9990 opzit, met 512 kB, en Kanji ROM. Er zit een + aansluiting op voor SCART. Deze kaart moet zo ongeveer � + 600,- kosten. + + Het is wel duur, maar zover ik weet zijn zij de enigen die + hem gaan leveren. + + + C O N C L U S I E + + Als deze VDP goed onder de MSX'ers verspreid zou worden, dan + ziet het er wel wat beter uit voor MSX, want deze VDP is zo + ongeveer te vergelijken met wat er in de Super Nintendo zit. + + En aangezien de Super Nintendo z'n kracht vooral haalt uit + z'n VDP, moet een turbo R er wel mee kunnen concurreren. + (Ware het niet dat de turbo R veel duurder is, maar daar + staat dan wel weer tegenover dat een turbo R voor andere + dingen dan spellen kan worden gebruikt.) + + Het zou mooi zijn, als deze VDP goed zou worden verkocht, + dan is de kans dat er spellen komen voor de V9990 heel wat + groter. Maar zoals het eruit zie, kopen alleen de + fanatiekelingen (zoals ik) zo'n ding, en komen er alleen wat + kleine programmaatjes. + + (Daarom kopen zo'n apparaat, want alleen dan kun je genieten + van HELE GAVE spellen op een MSX, je moet wel ongeveer een + half jaar wachten voordat de eersten er komen. Moet je maar + geduld hebben!) + + Erik Maas diff --git a/sunrise_special/4/VDP Cursus 5.md b/sunrise_special/4/VDP Cursus 5.md new file mode 100644 index 0000000..af4e05e --- /dev/null +++ b/sunrise_special/4/VDP Cursus 5.md @@ -0,0 +1,166 @@ + M S X 2 / 2 + V D P C U R S U S ( 5 ) + + + In dit vijfde deel worden de statusregisters behandeld. De + naam zegt het al, deze registers geven informatie over de + status van de Video Display Processor. Uiteraard kunnen + statusregisters alleen gelezen worden en niet beschreven. + + Het lezen van een statusregister is in deel 1 (Sunrise + Special #2) behandeld, daar kunt u dat nog eens nalezen. + + + O V E R Z I C H T S T A T U S R E G I S T E R S + + MSB 7 6 5 4 3 2 1 0 LSB + S#0 F 5S C ---vijfde sprite--- Status #0 + + F: Vertical scanning interrupt flag + Wordt geset als de VDP bovenaan het scherm begint + met de beeldopbouw. F wordt gereset als S#0 wordt + gelezen. Dit is de normale interrupt, die behalve + naar de hook &HFD9A ook naar de hook &HFD9F springt. + 5S: Flag voor de vijfde/negende sprite + Deze vlag geeft aan dat er meer sprites op een hori- + zontale lijn voorkomen dan de VDP kan weergeven. In + G3 (SCREEN 4) en hoger zijn dat er acht, in de ande- + re schermen vier. + C: Collision flag + Wordt gezet als twee sprites elkaar raken. + vijfde + sprite: Bevat het nummer van de vijfde of negende sprite. + + + MSB 7 6 5 4 3 2 1 0 LSB + S#1 FL LPS -Identification #- FH Status #1 + + FL: Lightpen flag (Lightpen flag is geset, LP bit 6 R#8) + Als de lichtpen licht waarneemt moeten zowel dit bit + als IE2 (bit 5 van R#0) geset zijn om een interrupt + te veroorzaken. FL wordt gereset als S#1 wordt + gelezen. + + Mouse Switch 2 (Mouse flag is geset, MS bit 7 R#8) + De 2e vuurknop van de muis is ingedrukt. FL wordt + niet gereset als S#1 wordt gelezen. + + LPS: Lightpen switch (Lightpen flag is geset) + De vuurknop van de lichtpen is ingedrukt. LPS wordt + niet gereset als S#1 wordt gelezen. + + Mouse switch 1 (Mouse flag set) + De 1e vuurknop van de muis is ingedrukt. LPS wordt + niet gereset als S#1 wordt gelezen. + + Identification number: + Het ID# van de VDP. Hieraan kun je zien of het V9938 + of V9958 is (bit 2 van S#1 is geset als V9958). + + FH: Horizontal scanning interrupt flag + FH wordt geset als een zgn. line-interrupt optreedt, + dus als de VDP begint met het weergeven van de lijn + die in R#19 staat. Er wordt een interrupt + gegenereerd als IE1 (bit 4 van R#0) is geset. FH + wordt gereset als S#1 wordt gelezen. + + Let op: de lichtpen- en muisuitlezing wordt bij de V9958 + niet meer door de VDP gedaan. De bits FL en LPS hebben dus + hun betekenis verloren. Bij MSX2 wordt het uitlezen van de + muis overigens ook al niet met de VDP gedaan. + + + MSB 7 6 5 4 3 2 1 0 LSB + S#2 TR VR HR BD 1 1 EO CE Status #2 + + TR: Transfer ready flag + Als de CPU (microprocessor) data naar de VDP stuurt, + moet er gewacht worden tot dit bit geset is. Dan mag + de data verstuurd worden. + + VR: Vertical scanning line timing flag + Tijdens verticaal scannen is deze flag geset. + + HR: Horizontal scanning line timing flag + Tijdens horizontaal scannen is deze flag geset. + + BD: Boundary color detect flag + Bij het Search commando (zie VDP cursus deel 4) + geeft deze flag aan of de randkleur is gevonden of + niet. + + EO: Display field flag + Geeft bij het afwisselend weergeven van pagina's aan + welke pagina er wordt weergegeven. + + CE: Command execute flag + Geeft aan dat een commando wordt uitgevoerd. Wacht + tot dit bit gereset is voordat het volgende commando + naar de VDP wordt gestuurd. Zie VDP cursus deel 3 en + 4. + + + MSB 7 6 5 4 3 2 1 0 LSB + S#3 X7 X6 X5 X4 X3 X2 X1 X0 Column low + S#4 1 1 1 1 1 1 1 X8 Column high + S#5 Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 Row low + S#6 1 1 1 1 1 1 Y9 Y8 Row high + + Bovenstaande registers worden gebruikt voor het aangeven van + de de plaats van de spritebotsing, de plaats van de lichtpen + of de relatieve beweging van de muis. Zie voor de + spritebotsing verderop. Lichtpen en muis worden niet via de + VDP uitgelezen. + + + MSB 7 6 5 4 3 2 1 0 LSB + S#7 C7 C6 C5 C4 C3 C2 C1 C0 Color reg + + Dit register wordt gebruikt bij de POINT en VRAM to CPU + commando's. De VRAM data staat in dit register. (Zie VDP + cursus deel 4). + + MSB 7 6 5 4 3 2 1 0 LSB + S#8 BX7 BX6 BX5 BX4 BX3 BX2 BX1 BX0 Border X low + S#9 1 1 1 1 1 1 1 BX8 Border X hig + + De X co�rdinaat die wordt gevonden bij het Search commando + wordt in deze registers gezet. (Zie VDP cursus deel 4). + + Nu we de theorie hebben behandeld komen er nog een aantal + toepassingen aan bod. + + + S P R I T E B O T S I N G + + Bij een spritebotsing wordt C (bit 5 van S#0) geset. Als + zowel MS als LP (bit 7 en 6 van R#8) zijn gereset, dan + zullen de co�rdinaten van de botsing naar S#3 t/m S#6 worden + geschreven. Let op: bij het lezen van S#5 wordt de inhoud + van S#3 t/m S#6 gereset. + + De X die in S#4 en S#3 staat is 12 meer dan de X van de + botsing, de Y die in S#5 en S#6 staat is 8 meer dan de + botsing. Oftewel: + + XS#3S#4 = XBOTSING + 12 + YS#5S#6 = YBOTSING + 8 + + + S C R E E N S P L I T + + Het is met de statusregisters zeer eenvoudig om een + nauwkeurige screensplit te maken. We gebruiken daarvoor HR + en FH. Eerst zetten we de lijn waarop de split moet optreden + in R#19. Vervolgens wachten we tot FH (bit 7 van S#1) wordt + gezet. Nu kunnen we de screensplit strak tegen de border + krijgen door HR uit te lezen. Als HR (bit 5 van S#2) is + geset begint de VDP met het weergeven van een nieuwe lijn. + Voer nu zo snel mogelijk de nodige akties uit, en de + screensplit is nagenoeg perfect. + + Een korte aflevering dit keer. De sprites en de + beeldschermopslag komen nog aan bod, daarna gaan we verder + met de toepassingen. De volgende keer neem ik u mee naar de + wereld van de sprites. + + Stefan Boer diff --git a/sunrise_special/4/VDP Curus 6.md b/sunrise_special/4/VDP Curus 6.md new file mode 100644 index 0000000..4297213 --- /dev/null +++ b/sunrise_special/4/VDP Curus 6.md @@ -0,0 +1,358 @@ + M S X 2 / 2 + V D P C U R S U S ( 6 ) + + + Zoals beloofd ga ik het deze keer hebben over sprites. + Voordat ik begin met het behandelen van de echte sprites, + wil ik eerst nog even een misverstand uit de wereld helpen. + + + S O F T W A R E S P R I T E S + + Misschien heeft u deze term wel eens gehoord of er iets over + gelezen. De doorsnee MSX'er weet wel dat er sprites bestaan, + maar dat er verschil zou zijn tussen softwaresprites en + hardwaresprites gaat de meesten boven de pet. En dat is ook + niet zo vreemd, want er bestaat maar ��n soort sprites op + MSX, de hardwaresprites. Voor alle duidelijkheid: dit zijn + de sprites die je in BASIC aanstuurt met PUT SPRITE en + SPRITE$. + + Wat zijn die softwaresprites dan wel? Dat zijn gewoon + plaatjes die gekopieerd worden. Die plaatjes staan dan op + een onzichtbare page en worden met een razendsnelle COPY + opdracht naar de zichtbare pagina gekopieerd. (Hoewel ik + hier spreek van 'razendsnel', betekent dat niet dat er een + HMMM (High-speed Move vraM to vraM) wordt gebruikt, dan kan + er geen TPSET worden gebruikt en dat is noodzakelijk bij + softwaresprites. Er wordt LMMM (Logical Move vraM to vraM) + gebruikt.) + + Softwaresprites hebben het voordeel dat het kleurgebruik + (zeker op SCREEN 8, op SCREEN 10 t/m 12 zijn softwaresprites + bijna onmogelijk) onbeperkt is, en dat ze in theorie elke + grootte kunnen hebben. In praktijk kunnen ze natuurlijk niet + te groot zijn, want dan duurt het kopi�ren zo lang dat het + niet meer mooi is. Uiteraard kunnen op de snelheidsduivel + turbo R grotere softwaresprites worden gebruikt, kijk maar + naar Seed of Dragon. + + De nadelen zijn ook niet mis: het is trager dan + softwaresprites, moeilijker aan te sturen (je moet alles + zelf doen) en het neemt meer VRAM in beslag. Bovendien is er + nog een probleem: als de softwaresprite zich verplaats moet + het VRAM dat eronder zat weer worden hersteld, dat is bij + gewone sprites niet nodig. + + Een ander voordeel van softwaresprites is nog dat er geen + maximum aantal sprites is en dat ze nooit kunnen gaan + knipperen, maar omdat deze problemen alleen bij grote + aantallen sprites voorkomen en de softwaresprites dan veel + te langzaam worden is dat niet zo'n groot voordeel. + + Hardwaresprites hebben tenslotte nog het voordeel dat je ze + heel makkelijk stil kunt laten staan terwijl je de rest van + het scherm laat scrollen (of dat nu hardwarematig (R#23 + verticaal / R#26 + R#27 horizontaal) of softwarematig (met + COPY) gaat). Softwaresprites zou je dan elke keer moeten + verplaatsen. + + De softwaresprites zullen behandeld worden bij de + toepassingen, die later in de cursus veelvuldig aan bod + zullen komen. Ik ben behoorlijk afgedwaald, laten we nu maar + beginnen met het onderwerp van deze keer: (hardware)sprites. + + + S P R I T E M O D E 2 + + Ik behandel hier alleen de zgn. SPRITE MODE 2, die in SCREEN + 4 en hoger wordt gebruikt. Dit is tenslotte een MSX2/2+ VDP + cursus, dus de MSX1 sprites slaan we over. + + Er zijn 32 sprites, genummerd van #0 tot en met #31. Een + sprite met een lager nummer heeft een hogere prioriteit. Er + kunnen maximaal 8 sprites op een horizontale lijn worden + getoond. Zijn er meer dan 8 sprites op een horizontale lijn, + dan worden de lijnen van de sprites met de laagste + prioriteit niet getoond. Het kan dus bijvoorbeeld gebeuren + dat een sprite voor de helft wegvalt. + + Als de ingekleurde delen van twee sprites elkaar raken + (botsen), zal bit 5 van S#0 worden geset. De co�rdinaten van + de botsing zullen in S#3 t/m S#6 worden gezet (zie VDP + cursus deel 5). + + Als er negen of meer sprites op een horizontale lijn staan, + dan zal bit 6 van S#0 worden geset. Bit 0-4 van S#0 zullen + dan het nummer bevatten van de negende sprite. + + Elke horizontale lijn van een sprite mag een eigen kleur + hebben uit het palet van 16 kleuren. + + De sprite prioriteiten kunnen worden uitgezet door het CC + bit van een lijn te setten (zie verderop), de overlappende + gedeeltes van twee sprites worden dan geORd. + + + S P R I T E R E G I S T E R S + + De grootte van de sprite wordt bepaald door bit 1 van R#1. + + MSB 7 6 5 4 3 2 1 0 LSB + R#1 0 BL IE0 M1 M2 0 SI MAG Mode reg. #1 + + SI = 1 : 16 x 16 pixels + SI = 0 : 8 x 8 pixels + + De sprite kan op normaal formaat of vier maal zo groot + worden weergegeven. Dit wordt bepaald door bit 0 van R#1. + + MAG = 1 : vergroot + MAG = 0 : normaal + + Met bit 1 van R#8 kan worden bepaald of de sprites aanstaan. + Als er geen sprites worden gebruikt, zet ze dan uit want dan + werkt de VDP sneller (meet het maar eens na, het scheelt + behoorlijk!). + + MSB 7 6 5 4 3 2 1 0 LSB + R#8 MS LP TP CB VR 0 SPD BW Mode reg. #2 + + SPD = 1 : disable sprites (zet sprites uit) + SPD = 0 : enable sprites (zet sprites aan) + + De vorm van de sprite staat in de Sprite Pattern Generator + Table. Er kunnen 256 patronen worden opgeslagen van elk 8 + bytes lang (#0 t/m #255). Het beginadres van een patroon is + als volgt te berekenen: + + + * 8 + + De kleuren van een sprite staan in de Sprite Color Table. + Behalve de kleuren worden er ook drie attribuutbits per lijn + opgeslagen. 8x8 sprites vergen 8 bytes, 16x16 sprites 16 + bytes. Het beginadres van de kleurinfo van een sprite is als + volgt te berekenen: (er is 1 positie per sprite, #0 t/m #31) + + + * 16 + + De overige attributen (coordinaten en patroonnummer) staan + in de Sprite Attribute Table, 4 bytes per sprite (#0 t/m + #31). Het beginadres van de attributen van een sprite is als + volgt te berekenen: + + + * 4 + + N.B. al deze tabellen staan in het VRAM. + + + S P R I T E A T T R I B U T E T A B L E + + Op + 0 staat de Y-co�rdinaat, 0 t/m 255. Is de + Y coordinaat gelijk aan 216, dan worden alle sprites met een + lagere prioriteit niet getoond, inclusief de sprite zelf. + Let op: de bovenste lijn van de sprite komt ��n lijn lager + dan de hier opgegeven y-co�rdinaat. + + Op + 1 staat de X-co�rdinaat, van 0 t/m 255. + Let op: ook in SCREEN 6 en 7 wordt de horizontale as voor + sprites in 256 stapjes verdeeld, en niet in 512! + + Op + 2 staat het patroonnummer. Hiermee wordt + aangegeven welk patroon uit de Sprite Pattern Generator + Table moet worden genomen. Let op: als de sprite grootte + 16x16 is, dan worden er vier patronen genomen voor ��n + sprite. Het maakt dan niet uit welke van de vier nummers je + opgeeft. Er zijn dus in feite maar 64 patronen bij 16x16 + sprites. + + MSB 7 6 5 4 3 2 1 0 LSB + R#5 A14 A13 A12 A11 A10 A9 1 1 Sprite attr. tab. + R#11 0 0 0 0 0 0 A16 A15 base adress reg. + + Het beginadres van de attribuuttabel is hier opgeslagen. Let + op: bit A9 is altijd 1. Door deze registers te manipuleren + is het mogelijk om de informatie van meer dan 32 sprites in + het VRAM op te slaan of om bijvoorbeeld PAGE 0 te tonen + terwijl de attribuuttabel ergens in PAGE 2 staat. + + + P A T T E R N G E N E R A T O R T A B L E + + In deze tabel staan de bit-matrices die de vorm van de + sprites bepalen. Het werkt heel simpel; 0 staat voor uit en + 1 voor aan. Een spookje uit Pacman zou er bijvoorbeeld zo + uit kunnen zien: + + &B00111100 + &B01111110 + &B11011011 + &B11011011 + &B11111111 + &B11111111 + &B11011011 + &B11011011 + + Voor elk patroon worden 8 bytes gebruikt. Er zijn totaal 256 + patronen, genummerd van #0 t/m #255. Bij 8x8 sprites krijgt + elke sprite ��n patroon, een 16x16 sprite krijgt er vier. + + MSB 7 6 5 4 3 2 1 0 LSB + R#6 0 0 A16 A15 A14 A13 A12 A11 Sprite patt. tab. + + Hier is het beginadres van de tabel opgeslagen. Door het + manipuleren met dit register kunnen bijvoorbeeld veel meer + dan 256 patronen gelijktijdig in het VRAM worden gezet, etc. + + + S P R I T E C O L O R T A B L E + + Elke horizontale lijn kan zijn eigen kleur krijgen (kleur 0 + is altijd transparant). Bovendien kunnen per lijn de sprite + prioriteit, de botsingsdetectie en de 'early clock' worden + aan- of uitgezet. + + Het beginadres van deze tabel ligt altijd precies 512 bytes + onder het beginadres van de Sprite Attribute Table. Per + Sprite (32 stuks, #0 t/m #31) worden er 16 bytes + gebruikt. Dat maakt totaal 512 bytes. Elke byte is als volgt + opgebouwd: + + MSB 7 6 5 4 3 2 1 0 LSB + EC CC IC 0 ----kleur------ + + EC: Early Clock, 1: verschuif lijn 32 bits naar links + CC: Priority Enable, 1: OR kleuren als sprites + overlappen + IC: Collision Detect, 1: negeer botsingen + + Bij CC=1 worden ook de botsingen niet gedetecteerd. + + + S P R I T E P R I O R I T E I T + + De sprite prioriteit wordt uitgezet als het CC-bit gelijk is + aan 1. De lijnen van een sprite waarvan CC gelijk is aan 1 + worden alleen getoond als er op diezelfde horizontale lijn + een sprite met een lager spritenummer voorkomt. + + Dit kan ook worden gebruikt om extra kleuren te cre�ren in + een samengestelde sprite (een 'sprite' die uit een aantal + afzonderlijke sprites is opgebouwd). Bijvoorbeeld: + + 888888-- ----4444 8888CC44 + 888888-- ----4444 8888CC44 + 888888-- + -------- = 888888-- + 888888-- 11------ 998888-- + 888888-- 11------ 998888-- + --222222 11------ 11222222 + -2222222 11------ 13222222 + 22222222 11------ 33222222 + + Op deze manier is het dus vrij eenvoudig om op een lijn drie + verschillende kleuren te krijgen, terwijl je maar twee + sprites gebruikt. + + + S P R I T E B O T S I N G + + Dit hebben we ook al bij de statusregisters behandeld, maar + voor de overzichtelijkheid behandelen we het nog maar een + keer. + + Als CC gelijk is aan 0 en gedeeltes van een sprite die geen + kleur 0 hebben overlappen elkaar, dan wordt er een sprite + botsing gedetecteerd. Bit 5 van S#0 wordt dan geset. Dit bit + wordt weer gereset als S#0 wordt gelezen. + + MSB 7 6 5 4 3 2 1 0 LSB + S#0 F 9S C ----9th sprite #--- Status reg. #0 + + C = collision, 9S = negen sprites/regel, 9th sprite # = + nummer van negende sprite. + + Als MS en LP niet geset zijn (R#8, muis en lichtpen, bij + V9958 niet aanwezig), dan worden de co�rdinaten van de + botsing in de statusregisters S#3 t/m S#6 gezet: + + MSB 7 6 5 4 3 2 1 0 LSB + S#3 X7 X6 X5 X4 X3 X2 X1 X0 Status reg. #3 + S#4 1 1 1 1 1 1 1 X8 Status reg. #4 + S#5 Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 Status reg. #5 + S#6 1 1 1 1 1 1 1 Y8 Status reg. #6 + + Van de X co�rdinaat moet nog 12 worden afgetrokken en van de + Y co�rdinaat 8. + + + S P R I T E K L E U R E N + + In SCREEN 5, 7, 10, 11 en 12 zijn de kleuren van de sprites + gelijk aan de kleuren uit het palet. In SCREEN 8 worden + andere kleuren gebruikt: + + Kleurcode: Groen: Rood: Blauw: + ---------------------------------------------------- + 0 0 0 0 transparant + 1 0 0 2 d. blauw + 2 0 3 0 d. rood + 3 0 3 2 d. magenta + 4 3 0 0 groen + 5 3 0 2 blauw/grijs + 6 3 3 0 oker + 7 3 3 2 grijs + 8 8 7 2 zalmrose + 9 0 0 7 blauw + 10 0 7 0 rood + 11 0 7 7 magenta + 12 7 0 0 l. groen + 13 7 0 7 cyaan + 14 7 7 0 geel + 15 7 7 7 wit + ---------------------------------------------------- + + SCREEN 6 is ook een speciaal geval, omdat er dan maar vier + kleuren zijn. Die kleuren worden ook in de sprites gebruikt + en het palet kan aangepast worden. Je kunt hier 'gestreepte' + sprites maken. De kleurcode wordt als volgt geinterpreteerd: + + MSB 3 2 1 0 LSB + -even-- -oneven Kleurcode (0-15) + + De bovenste twee bits worden gebruikt voor de kleur van de + oneven pixels en in de onderste twee bits staat de kleur van + de oneven pixels. Beide kleuren kunnen liggen tussen 0 en 3. + + + T P E N S P R I T E S + + Bit 5 van R#8 (TP) geeft aan of kleur 0 transparant is of + dat kleur 0 gewoon als paletkleur kan worden gebruikt. In + samenhang met sprites zijn er twee situaties: + + TP=0: (gedeeltes van) sprites met kleurcode 0 worden niet + getoond, op die plaats kan dan ook geen botsing worden + gedetecteerd. + + TP=1: (gedeelte) van sprite met kleurcode 0 wordt wel + getoond, volgens de paletkleur (in SCREEN 8 altijd zwart), + spritebotsingen worden normaal gedetecteerd. + + + T O T S L O T + + Voor het aansturen van sprites is schrijven naar het VRAM + noodzakelijk. Lees de procedures daarvoor nog maar eens na + in deel 1 van de cursus. Het geeft bijvoorbeeld een enorme + snelheidswinst om eerst de VDP klaar te zetten voor het + schrijven van data vanaf een bepaald adres, en vervolgens de + data rechtstreeks naar Port #0 (port &H98) te sturen. Bij + sprites moeten er toch vaak achterelkaar liggende adressen + worden beschreven. + + Waarschijnlijk zal er in VDP Cursus deel 15 (die komt op + Sunrise Magazine #10) een routine met sprites worden + behandeld. + + Veel succes met sprites op MSX en tot de volgende keer. + + Stefan Boer diff --git a/sunrise_special/4/Werken met ASCII C deel 2.md b/sunrise_special/4/Werken met ASCII C deel 2.md new file mode 100644 index 0000000..bb518ad --- /dev/null +++ b/sunrise_special/4/Werken met ASCII C deel 2.md @@ -0,0 +1,346 @@ + H E T W E R K E N M E T A S C I I C + + + + D E E L 2 + + C M E T A S S E M B L E R + + Hoewel ASCII C behoorlijk goede machinecode genereert, is + het soms toch handig om bepaalde routines in assembler te + schrijven. Zo is het bijvoorbeeld niet mogelijk om direct de + BIOS aan te roepen, hier is toch weer een library functie + voor nodig. Ook VDP I/O kan het beste in assembler worden + gedaan, omdat dit toch een stuk sneller gaat. + + Gelukkig is dit met ASCII C geen enkel probleem, het is + namelijk mogelijk om een library in assembler te schrijven + en de functies die in deze library staan, vervolgens te + gebruiken vanuit een C programma. + + Als de library goed wordt opgezet is het zelfs mogelijk om + uit 1 enkele source file zowel de .TCO file voor de + parameter checker te maken, als de .REL file voor de linker. + + In dit deel van de cursus zullen achtereenvolgens de + volgende onderwerpen worden besproken: + + - Het doorgeven van variabelen aan de functies. + - Het opzetten van de source zodat er zowel een .TCO als + een .REL file van gemaakt kan worden. + - Een voorbeeld library. + + + V A R I A B E L E N D O O R G E V E N + + ASCII-C kent 2 typen functies: + + - Fixed parameter functies: de functie heeft een vast aantal + parameters. + - Variabele parameter functies: de functie heeft een + variabel aantal parameters. + + Normaal gaat de C-compiler er uit dat een functie van het + fixed parameter type is. Een variabele parameter functie + moet eerst als volgt gedeclareerd worden: + + int func(.); + + Bij een fixed parameter functie worden de eerste 3 + variabelen in de Z80 registers doorgegeven, de rest wordt + allemaal op de stack gezet. Hierbij wordt de volgende + conventie gebruikt: + + parameter | char | niet-char + -----------+--------+--------------- + 1e | A | HL + 2e | E | DE + 3e | C | BC + 4e | (SP+2) | (SP+2, SP+3) + 5e | (SP+4) | (SP+4, SP+5) + etc. + + Bij een variabele parameter functie wordt het aantal + variabelen in HL gezet, en de rest wordt op de stack + gepushed. De volgorde is hierbij weer hetzelfde als bij een + fixed parameterfunctie, dus de variabelen worden als volgt + doorgegeven: + + parameter | char | niet-char + -----------+--------+--------------- + aantal vars| HL | HL + 1e | (SP+2) | (SP+2, SP+3) + 2e | (SP+4) | (SP+4, SP+5) etc. + + Als de functie een bepaalde waarde berekent, dan moet deze + ook weer worden teruggegeven aan de aanroepende functie, dit + gaat altijd via de registers. Als het functie type char is, + dan wordt de waarde teruggegeven in de A en in het andere + geval komt ze terug in HL. + + Een functie mag in principe alle registers veranderen. + + Voorbeeld: + + Stel je wilt een functie schrijven die aan karakter afdrukt + via de MSX1 main rom (CHPUT: adres 00A2H), en een functie + die een karakter van het toetsenbord leest (CHGET: adres + 009FH). Je zult deze functies dan moeten declareren in het C + programma dat er gebruik van gaat maken. Om dit te bereiken + kun je het beste alle declaraties die nodig zijn voor je + library bij elkaar zetten in 1 header file die je dan + include vanuit je C programma's. In deze header file moeten + dan de volgende declaraties staan: + + void bchput(); /* zet karakter via bios op scherm */ + char bchget(); /* lees karakter uit via bios */ + + In de assembly source (mlvb1.mac) zet je vervolgens de + volgende routines: + + bchput:: ld ix,0a2h ;Druk karakter in A + jr domsx1 ; af via de BIOS + + bchget:: ld ix,09fh ;Lees een karakter + domsx1: ld iy,(0fcc0h) ; en zet dat in A + jp 01ch + + end + + + Deze source kun je assembleren met: + + M80 = MLVB1 /Z + + om het bestand MLVB1.REL te maken. + + In een C programma (CVB1.C) kun je ze dan als volgt + gebruiken: + + typedef char void; + + void bchput(); + char bchget(); + + void main() + { + char test; + + do { + test = bchget(); /* Lees karakter uit via bios */ + bchput(test); + } while (test != 13); + } + + Deze listing kun je vervolgens compileren, assembleren en + linken met: + + CF CVB1 + CG -K CVB1 + M80 = CVB1 /Z + L80 CVB1,MLVB1,CVB1/N/Y/E:MAIN@ + + Als je dit allemaal hebt gedaan, dan heb je nu een (klein) + programma met de naam CVB1.COM, waarmee je kunt typen tot je + op de return toets duwt. + + + Z O W E L . T C O A L S . R E L V E R S I E + + V A N E E N S O U R C E + + Zoals je in bovenstaand voorbeeld wel kunt zien is het niet + zoveel werk om C te combineren met assembler. Het wordt + echter iets meer werk als je de library netter wilt + opzetten. + + In het bovenstaande voorbeeld kun je bijvoorbeeld geen + gebruik maken van de functie parameter checker (FPC) om te + kijken of het type van de variabelen wel klopt. + + Ook de linker wordt nu niet optimaal benut. Met L80 is het + namelijk mogelijk om een library zo samen te stellen dat + alleen functies die gebruikt worden, ook worden meegelinkt. + + Om dit te bereiken moet de source echter worden opgesplitst + in allemaal losse sources (��n source per onafhankelijke + functie). Deze sources moeten vervolgens allemaal los + geassembleerd worden (zodat er allemaal losse .REL files + ontstaan), en deze .REL files kunnen dan met LIB80 aan + elkaar worden gekoppeld tot 1 grote library. + + Om nu te voorkomen dat je disk vol komt te staan met + honderden losse library routines heeft ASCII corporation het + hulp programma MX gemaakt. Dit programma splitst 1 grote + source op in losse deel sources, maakt een batchfile aan om + deze sources afzonderlijk te assembleren en weer te deleten + en om vervolgens de .REL files te linken tot 1 .LIB file. + + Om goed gebruik te maken van MX moet de source echter wel + goed zijn opgezet. Hierbij wordt gebruik gemaakt van het + feit dat M80 een macro assembler is. In je source dien je 3 + (verder lege) macro's te defini�ren: + + module macro + endm + + endmodule macro + endm + + extrn macro + endm + + Alles wat in principe echt bij elkaar hoort kun je + vervolgens tussen MODULE FILENAME en ENDMODULE zetten. + Indien je vanuit dit stuk machinecode ook nog routines wilt + aanroepen die in een andere module staan, dan dien je deze + routines te declareren met EXTRN ROUTINE. + + MX zal dan alles wat tussen MODULE en ENDMODULE staat in het + bestand met de naam FILENAME zetten. In dit bestand worden + dan de EXTRN ROUTINE declaraties omgezet in de normale + EXTERN ROUTINE declaraties die nodig zijn voor M80. + + Het is wel belangrijk dat je de juiste volgorde aanhoudt als + bepaalde routines gebruik maken van andere routines: + + Als een routine uit MODULE A gebruik maakt van een routine + uit MODULE B, dan dient MODULE B VOOR MODULE A in de source + te staan!! + + Als we bij het bovenstaande voorbeeld blijven, dan kunnen we + de volgende source maken (met de naam MLVB2.MAC): + + module macro + endm + + endmodule macro + endm + + extrn macro + endm + + MODULE DOMSX1 + domsx1:: ld iy,(0fcc0h) + jp 01ch + ENDMODULE + + MODULE BCHPUT + extrn domsx1 ;Deze routine is nodig + bchput:: ld ix,0a2h ;Zet karakter op scherm + jp domsx1 + ENDMODULE + + MODULE BCHGET + extrn domsx1 + bchget:: ld ix,09fh ;Lees karakter uit + jp domsx1 + ENDMODULE + + end + + + Deze nieuwe source kun je nog altijd direct assembleren met + M80. Wil je er echter een library van maken waaruit alleen + de functies worden meegelinkt die aangeroepen worden, dan + dien je de volgende stappen te ondernemen: + + - Zorg ervoor dat AREL.BAT op je disk staat + - Zorg ervoor dat MX.COM, M80.COM en LIB80.COM op je disk + staan. + - Typ in: + MX -L MLVB2 > TEMP.BAT TEMP REN MLVB2.LIB MLVB2.REL + + Deze nieuwe library kun je vervolgens meelinken met: + + L80 CVB1,MLVB2/S,CVB1/N/Y/E:MAIN@ + + De /s achter mlvb2 betekent dat L80 alleen die modules moet + meelinken waar routines in zitten die worden aangeroepen. + + In het eerste C voorbeeld worden zowel bchput als bchget + gebruikt. Ze zullen in dit geval dan ook beiden worden + meegelinkt en er is nu dus geen echt voordeel behaald. In + het volgende voorbeeld is het gebruik van de (lastigere) + methode via MX wel al voordeliger (CVB2.C): + + typedef char void; + void bchput(); + + void bputstr(string) + char *string; + { + while (*string) + bchput(*string++); + } + + void main() + { + bputstr("Dit is C voorbeeld 2"); + } + + Deze listing kun je vervolgens compileren, assembleren en + linken met: + CF CVB2 + CG -K CVB2 + M80 = CVB2 /Z + L80 CVB2,MLVB2/S,CVB2/N/Y/E:MAIN@ + + CVB2.COM zal nu 58 bytes groot zijn. Indien je echter met de + oude library had gelinked (middels l80 + cvb2,mlvb1,cvb2/n/y/e:main@), dan was CVB2.COM echter 61 + bytes groot geweest omdat dan ook de overbodige bchget was + meegelinked. + + Om ook nog gebruik te kunnen maken van de functie parameter + checker (fpc), dient de source nog iets uitgebreid te + worden. Om FPC te gebruiken, moeten namelijk lege C body's + worden opgenomen zodat FPC weet hoeveel en wat voor type + parameters gebruikt worden door de functie. Aangezien de + source hiervoor echter door CF.COM en door M80.COM gehaald + moet kunnen worden, is er een klein probleem (de programma's + verwachten namelijk een compleet verschillende syntax). Door + nu echter van een truuk gebruik te maken, kunnen evengoed de + lege C routine body's en de echte ML routines in ��n enkele + source worden gebruikt. De truuk bestaat eruit dat ; voor + M80 betekent dat er commentaar begint (en dat alles wat er + achter staat dus niet van belang is), terwijl het voor CF + een scheidings teken tussen te statements is, dus CF negeert + een losse ;. + + De source kan dan beginnen met "; /*". Alles wat daarna op + dezelfde regel staat, is dan zowel voor M80 als voor CF + commentaar. Door hierna goed af te wisselenen met /* en */ + (voor CF) en .comment # en # voor M80, is het mogelijk om + alles in 1 source te houden. + + + E E N V O O R B E E L D L I B R A R Y + + De library XS-CLIB1.MAC is de volledig ontwikkelde versie + van de eerste voorbeelden. Er zitten ook nog een paar + functies bij om de VDP aan te sturen. De volledig afgewerkte + library staat tevens op de disk (XS-CLIB1.REL). Om er + gebruik van te maken, dient de parameter XS-CLIB1/S te + worden opgenomen achter L80 in in de batchfile waar je + normaal je C programma's mee linkt. Om de functies te + gebruiken, dien je ook nog de header file XS-CLIB1.H op te + nemen in je source. + + Met CF.COM kan uit deze source nu de .TCO file voor de + function parameter checker worden gehaald. De library zelf + kan worden aangemaakt met MX.COM. Het aanmaken van + XS-CLIB1.TCO en XS-CLIB1.REL gaat nu als volgt: + + - Zorg ervoor dat CF.COM, MX.COM, M80.COM, LIB80.COM en + AREL.BAT op de disk staan. + - Typ in: cf xs-clib1.mac om de .TCO file te maken. + - En typ vervolgens in: + MX -L XS-CLIB1 > TEMP.BAT TEMP + REN XS-LIB1.LIB XS-LIB1.REL + om XS-CLIB1.REL te maken. + + Het bestand XS-VB.C is een voorbeeld van het gebruik van + deze library. Dit bestand is te compileren met MK-XSVB.BAT. + + Alex Wulms diff --git a/sunrise_special/5/C Cursus deel 6.md b/sunrise_special/5/C Cursus deel 6.md new file mode 100644 index 0000000..ffb0257 --- /dev/null +++ b/sunrise_special/5/C Cursus deel 6.md @@ -0,0 +1,338 @@ + C C U R S U S D E E L 6 - 1 + + + + 1 . I N L E I D I N G + + Dit deel is bedoeld als afsluiting van de cursus. Denk nu + niet dat iemand door slechts deze zes tekstfiles te lezen + een volleerde C programmeur zal zijn, maar het is een basis. + Op een tweetal zaken na (en die worden direkt hierna + besproken) is zo ongeveer de hele taal C de revue + gepasseerd. Maar kennis van de taal is niet voldoende om er + goede programma's in te kunnen schrijven, ervaring is ook + van belang, en we kunnen de kunst ook gedeeltelijk afkijken, + gewoon door bestaande C-sources te bestuderen. + + Maar aangenomen dat we een project van enige omvang in C + willen uitvoeren - ik mag er toch wel van uitgaan dat deze + files niet alleen gelezen worden omdat 't plot zo spannend + is? - hoe kunnen we dan zoiets het beste aanpakken? Dat komt + in hoofdstuk 3 ter sprake. + + De hoofdstukken 4 gaat over het debuggen van C-programma's, + en hoofdstuk 5 behandelt de ontwikkeling van een vrij groot + voorbeeldprogramma. Deze laatste twee hoofdstukken worden in + de volgende Sunrise Special gepubliceerd. + + + 2 . N O G T W E E S T A T E M E N T S + + Al enige tijd terug heeft iemand mij erop gewezen dat ik + (foei toch!) een tweetal statements ben vergeten te + bespreken. Dat klopt inderdaad, maar tot mijn verdediging + wil ik dan wel aanvoeren dat deze twee statements in + principe geen extra mogelijkheden aan ons repertoire + toevoegen. + + + 2 . 1 H E T F O R - S T A T E M E N T + + Iedere programmeertaal schijnt een for-statement te moeten + hebben, en C is daar geen uitzondering op. Maar in C is het + niet nodig hem te gebruiken als simpele teller, zoals zal + blijken. De syntax is als volgt: + + for (; ; ) + + Heel obscuur. Maar het wordt wel duidelijker als we het + equivalente while-statement laten zien: + + ; + while () { + + ; } + + Toch is er een klein verschil: een continue-statement brengt + ons bij , en niet naar het begin van de while lus. Een + break-statement daarentegen doet in beide gevallen precies + hetzelfde. + + De meest gebruikelijke manier om een for-statement te + gebruiken is als volgt: + + for (cntr = 0; cntr < 60; cntr++) printf("%d ", cntr); + + Hier wordt het statement inderdaad als simpel tellertje + gebruikt, en de getallen 0 t/m 59 worden op het scherm + gezet. (De variabele 'cntr' is trouwens na afloop 60, hou + daar rekening mee!) + + We hoeven overigens niet alledrie de uitdrukkingen in het + for-statement te gebruiken: we mogen ze eventueel zelfs + alledrie weglaten, maar als we de middelste weglaten + ontstaat een eindeloze lus, die we alleen met een 'break' + kunnen verlaten. Sommige programmeurs geven de voorkeur aan + een + + for(;;) + + boven een + + while(TRUE) + + als ze zo'n eindeloze lus willen, maar dat is een kwestie + van persoonlijke stijl en smaak. + + + 2 . 2 H E T S W I T C H S T A T E M E N T + + Hoewel de functie van een switch-statement in principe ook + door het gebruik van if-statements kan worden gesimuleerd, + is het toch erg nuttig, en dan met name omdat het programma + er een stuk overzichtelijker van kan worden. Het komt + ongeveer overeen met het CASE-statement in PASCAL of in + mindere mate met de ON..GOTO in BASIC. Helaas is de syntax + een beetje lastig, maar het went snel genoeg: + + switch() + + En de syntax van het switch-block: + + { + + ... + [default: ] } + + Voor lees: een willekeurig aantal (ook nul!) + statements. De ... geeft aan dat een switch-block uit een + willekeurig aantal case-labels en bijbehorende statements + kan bestaat. Het default-label is optioneel, zoals aan de + vierkante haken is te zien. + + Case-labels hebben de vorm: case : + + Ok, dat is dus een switch-statement, maar wat doet 't nu + precies? Wel, eigenlijk is het heel eenvoudig: vanaf de + 'switch' wordt gesprongen naar het statement volgend op het + case-label waarvan de overeen komt met de waarde + van . Indien zo'n label niet bestaat wordt er naar het + statement volgend op 'default:' gesprongen, en als dat niet + bestaat wordt geen enkel statement in het switch-block + uitgevoerd, en gaat het programma gewoon verder. Een + voorbeeldje, snel, voor de hersens overbelast raken: + + switch(getch()) { + case 'j': + case 'J': printf("U drukte op de 'J'\n"); + break; + + case 'n': + case 'N': printf("U drukte op de 'N'\n"); + break; + + default: printf("U heeft 't niet begrepen...\n"); } + + Met getch() halen we een karakter van het toetsenbord + binnen, en afhankelijk van welke dat is springen we naar een + van de case-labels. Is het een 'j' dan vervolgen we na 'case + 'j':', en vanaf daar vervolgt het programma zijn weg, en + komt dan de printf-functie tegen. De case-labels zijn + uiteraard geen statements, ze dienen slechts om een bepaalde + plek in het switch-block aan te geven. De breakstatements, + dat ons het switch-block doen verlaten, zijn dan ook + essentieel, anders zou er komen te staan: + + U drukte op de 'J' + U drukte op de 'N' + U heeft 't niet begrepen... + + Dat levert wel weer wat hoognodige inspiratie voor + Sinterklaasgedichten, de komende december, maar verder heb + je er niet veel aan. Dit is een belangrijk verschil met een + taal als PASCAL, waar in een CASE-statement slechts die + statements uitvoert die bij het betreffende label horen. C + is wat dat betreft - trouw aan z'n reputatie - moeilijker, + maar flexibeler, en daar hebben we in bovenstaand voorbeeld + gebruik van gemaakt om de invoer niet in hoofdletters te + hoeven omzetten. + + Misschien ten overvloede: we mogen natuurlijk ook switch- + statements maken met int's of unsigned's in de 'switch', en + de constanten in de case-labels mogen elke vorm hebben: alle + constanten worden intern geconverteerd naar hetzelfde type + als de uitdrukking in de 'switch'. + + + 3 . G R O T E R E P R O J E K T E N I N C + + Wie vol goede moed een programmaatje in C begint te + schrijven, en er vervolgens hier en daar wat functies bij- + maakt merkt al gauw tot zijn grote schrik dat de source + sneller groeit dan het financieringstekort op de Russische + [Nvdr. Eh... is het niet GOSsische?] begroting, en bovendien + al even ondoorzichtig wordt. Ai, daar zitten we nu met onze + goede voornemens: het is dan wel niet zo'n zooitje als het + gemiddelde BASIC-programma (eh, we hebben onze variabelen + tenminste wel fatsoenlijke namen gegeven, niet?) maar een + hoop van onze functies beginnen al een paar honderd regels + lang te worden, omdat we in die functies steeds weer nieuwe + taken hebben ondergebracht. En ondertussen doet de compiler + er twintig minuten over om het programma te compileren, en + we hebben onze B: drive al afgekoppeld omdat de compiler + anders te weinig geheugen heeft... + + Klinkt dat bekend in de oren? Nou ja, we trappen er alle- + maal wel eens in, het begint allemaal zo klein, zo simpel. + Misschien is het wel tijd om een paar gouden regels op + papier te zetten: + + + P R O G R A M M E E R M O D U L A I R ! + + Dit is het krachtigste hulpmiddel om grote projecten + overzichtelijk te houden. In tegenstelling tot bijv. PASCAL + mag het programma namelijk in verschillende, kleinere + sources gesplitst worden, die apart gecompileerd mogen + worden. Pas in de laatste stap wordt dan alles samengevoegd + door onze linker. + + Hiermee worden we op verschillende manieren geholpen. Zo + gaat het compileren van kleine sources natuurlijk veel + sneller dan grote, en de compiler zal veel minder snel + geheugenproblemen krijgen. Het dwingt ons bovendien de + functies in logische, bij elkaar behorende groepen te + verdelen. Hierdoor wordt de logica (of het gebrek eraan) van + het programma veel duidelijker zichtbaar. Als we erg veel + moeite hebben om een logische opdeling te maken zijn de + functies waarschijnlijk te groot, en hebben elk teveel + taken. + + + H O U H E T K L E I N + + Zijn onze functies te groot en meer dan 50 regels is in + feite al te groot, en ongeveer 25 regels (een scherm vol) is + waarschijnlijk beter dan moeten we bovenstaand principe + gebruiken om onze functies te vereenvoudigen. In feite + moeten we in een enkele zin kunnen zeggen wat een functie + precies doet, en die zin moeten we dan als commentaarregel + voor de functie zetten, zoals: + + /* Haal de default-configuratie uit DEFAULT.CNF */ + + + K I S S + + Een acroniem: Keep It Simple and Stupid. Je kan dit zien als + een uitbreiding van voorgaande regel, en waarschuwt ons het + allemaal niet te mooi te willen doen. Een simpele (en + eenvoudig te begrijpen) routine laat zich gemakkelijker + aanpassen als in de loop van het programmeren de eisen eraan + iets veranderen, en zal minder snel voor subtiele bugs + zorgen. Als het programma klaar is en werkt kunnen we altijd + nog hier en daar de zaak optimaliseren. (De ervaring leert + echter dat we tegen die tijd allang blij zijn dat 't af is!) + Performance-freaks wil ik hier graag wijzen op de 90%-10% + regel, een vuistregel die erop neerkomt dat een programma + 90% van de tijd doorbrengt in slechts 10% van de code. Enige + prestatieverbetering is alleen dan te verwachten als we die + 10% aanpakken. Voor 90% van het programma blijft dan gewoon + de KISS-regel van toepassing. + + + I N F O R M A T I O N - H I D I N G + + Een principe wat vooral de betrouwbaarheid van een programma + ten goede zal komen is "information hiding". Hiermee wordt + bedoeld dat we een taakverdeling kiezen waardoor (groepen) + functies zoveel mogelijk onafhankelijk van elkaar opereren. + Zo is een MODEM-functie natuurlijk het gemakkelijkst te + gebruiken als we er eenvoudig karakters naar kunnen + schrijven, of ervan kunnen ontvangen zonder dat we ons druk + hoeven maken hoe dat verder gebeurt. Het eerste wat we in + zo'n geval doen is de MODEM-functie van een buffer voorzien + voor inkomende en uitgaande data: hierdoor wordt deze + functie veel makkelijker in het gebruik, omdat we geen + rekening meer hoeven houden met de precieze tijd waarop een + karakter arriveert. We "verbergen" dus de exacte + ontvangsttijd (die is meestal toch onbelangrijk). + + Maar we kunnen buffers niet onbeperkt groot maken: helemaal + kunnen we dus de tijdfactor niet uitschakelen. We zouden + echter kunnen overwegen om de MODEM-functie automatisch een + XOFF te laten sturen als de buffer - zeg - tweederde vol is, + en een XON al hij weer voor maar eenderde vol is. In dat + geval hebben we dus de fysieke manier van communiceren + helemaal afgeschermd van de rest van het programma, die naar + believen de informatie kan krijgen en verwerken. + + Dit voorbeeld maakt duidelijk hoe we een taakverdeling + kunnen kiezen die maakt dat functies elkaar zoveel mogelijk + als een simpele "black-box" zien, die zich niet druk hoeven + te maken hoe de anderen precies werken. Maar natuurlijk + mogen we geen belangrijke informatie verbergen: bovenstaande + MODEM-functie zou geen genade kunnen vinden in de "ogen" van + een ZMODEM-protocolfunctie, omdat in protocollen de timing + wel degelijk van belang is. Maar in dat geval kunnen we wel + weer een andere taakverdeling vinden door bijv. de + MODEM-functie de data alvast per frame te laten ontvangen: + dan wordt de timing voor de rest van het protocol weer + minder kritisch! + + Bovenstaand voorbeeld is natuurlijk niet meer dan dat: een + voorbeeld, en probeer het onderliggende principe in ieder + geval daarvan los te zien. Het is in ieder geval goed + gebruik om het aantal parameters van een functie te beperken + tot de essentiele (bij voorkeur vier of minder) en zo min + mogelijk van systeemvariabelen gebruik te maken (tenzij die + binnen het programma vrij constant zijn, zoals bijv. de + screen-mode). + + + E N T O T S L O T + + Hou het N E T J E S E N O V E R Z I C H T E L I J K !! + + Een paar tips: laat de regels netjes inspringen binnen + lussen en if..else statements en wees consequent hierin. + Ikzelf vind het prettigst om twee spaties in te springen, + maar sommigen vinden vier, of zelfs meer, overzichtelijker. + Een kwestie van smaak. + + Indien er veel regels staan tussen het begin van een lus en + het eind ervan werkt het vaak verduidelijkend om in een + stukje commentaar aan te geven waar het einde van de lus is, + zo ongeveer: + + while (ptr != NULL && *ptr != '\0') { + + } /* while (ptr !=... */ + + Gebruik voldoende commentaar, maar overdrijf niet. Geef wel + altijd (kort) aan wat een functie geacht wordt te doen, en + geef bij belangrijke (voornamelijk globale) variabelen aan + waar ze voor staan als dit al niet uit de naam duidelijk + wordt. + + Probeer een systeem aan te leggen in de keuze van namen. De + namen 'tmp' of 'temp', of zij die ermee beginnen of eindigen + zijn bij mij altijd tijdelijke variabelen, en andere + veelgebruikte (delen van) namen zijn 'src' (source = bron), + 'dst' (destination = bestemming), 'count' of 'cnt' (aantal), + 'siz' of 'size' (grootte), 'ptr' (pointer), 'x' en 'y' + (coordinaten) en 'buf' (buffer). Combinaties zijn ook + mogelijk, bv. 'bufsize', waaruit direkt blijkt dat het hier + de grootte van een buffer betreft. + + Met '#define' gedefinieerde constanten horen altijd in + HOOFDLETTERS. Dit is algemeen gebruikelijk onder de + C-programmeurs, die het meestal toch maar zelden met elkaar + over iets eens zijn. + + En tot slot, als je echt een flink project aan de broek + hebt: maak je aantekeningen in een LOGBOEK (blocnote, oud + schrift, etc.) zodat het gemakkelijker wordt zelfs na lange + tijd nog eens op het project terug te komen. + + Robert Amesz diff --git a/sunrise_special/5/Fout vertaler.md b/sunrise_special/5/Fout vertaler.md new file mode 100644 index 0000000..8e2454b --- /dev/null +++ b/sunrise_special/5/Fout vertaler.md @@ -0,0 +1,26 @@ + F O U T V E R T A L E R + + + This TSR is downloaded in BBS Roefsoft, and translates all + error messages of MSX-BASIC 2.1 and disk-BASIC 1.0 into + Dutch. The effect of this is rather funny! + + + F I L E N I E T G E V O N D E N + + This is, as was to be expected, the translation of "File not + found". Actually it should be "Bestand niet gevonden". But + it's comical enough without "bestand". It's also a bit weird + that the TSR is called "Error Translator", and not + "Fout Vertaler". + + I hope nobody really needs this TSR, for the one who does + need it, can't play a single decent MSX-game, and can't + understand any scroll-text - and he can't even read this + text, and so he wouldn't even know the program would exist! + + Kasper Souren + + + P.S. The file ET.TSR is the meant TSR and you can find it on + this disk. diff --git a/sunrise_special/5/Frequenty analyzer.md b/sunrise_special/5/Frequenty analyzer.md new file mode 100644 index 0000000..b16ed04 --- /dev/null +++ b/sunrise_special/5/Frequenty analyzer.md @@ -0,0 +1,20 @@ + F R E Q U E N C Y A N A L Y Z E R + + + Met FRQANAL.BAS is het mogelijk om op je turbo R samples te + onderzoeken op frequenties. Eerst wordt een stukje + gesampled, en dat wordt dan onderzocht. Vervolgens kun je + met de muis kijken welke frequentie veel voorkomt. + + DTMF.BAS doet hetzelfde, maar kijkt alleen maar naar de + druktoetsfrequenties, en geeft daarna op welke toets het + geweest is. Het werkte goed met mijn telefoon, al moet je + natuurlijk wel de juiste kant van de hoorn bij de microfoon + houden. + + Zonder KUN-BASIC werkt FRQANAL.BAS niet, en DTMF.BAS slechts + zeer langzaam. FRQANAL gebruikt namelijk ook een stukje + machinecode. Dat is eventueel wel om te zetten, maar wie + heeft nou niet de beschikking over KUN-BASIC? + + Kasper Souren diff --git a/sunrise_special/5/Gestruktureerd programmeren.md b/sunrise_special/5/Gestruktureerd programmeren.md new file mode 100644 index 0000000..180e585 --- /dev/null +++ b/sunrise_special/5/Gestruktureerd programmeren.md @@ -0,0 +1,264 @@ + G E S T R U C T U R E E R D P R O G R A M M E R E N + + + Vanaf de volgende Special ga ik een aantal teksten schrijven + over gestructureerd programmeren in machinetaal. Veel + programmeurs, zowel beginners als gevorderden, programmeren + niet gestructureerd en denken dat zij daardoor sneller + programmeren en dat hun programma's sneller zijn. Hoewel + mijn artikelen juist voor die programmeurs zijn bedoeld, + zullen zij daarom vaak aan hun oude stijl vasthouden. + + Ik was daarom van plan om een uitgebreid verhaal te + schrijven waarom het beter is om gestructureerd te + programmeren. Ik heb echter (erg) weinig tijd momenteel, en + kwam daarom het idee om de tekst die Alex van der Wal ruim + twee jaar geleden schreef over dit onderwerp hier "af te + drukken". Ik hoop dat iedereen na het lezen van onderstaande + tekst "bekeerd" is! + + Vanaf de volgende Special kunt u van mij een serie artikelen + verwachten over gestructureerd programmeren volgens de + methode van stapsgewijze verfijning (oftewel top-down). Tot + dan! + + Stefan Boer + + + I N L E I D I N G + + Er zijn nogal wat mensen onder jullie die zichzelf + programmeur noemen, maar vaak blijkt dan dat ze dat heilige + woord misbruiken. Een programmeur is nl. iemand die een + probleem onder de loep neemt en die daarna via vaste regels + en instrukties tot een oplossing komt. Dat betekent dat zijn + programma aan een aantal standaard voorwaarden voldoet. + + De belangerijkste afspraak waar hij zich aan moet houden is + dat het programma dat hij geschreven heeft ook voor andere + programmeurs ontcijferbaar moet zijn zonder dat je dagen + bezig bent om alles te begrijpen. Het is echter helaas een + feit dat mensen die bezig zijn om de kunst van het + programmeren te leren deze afspraak negeren. Vaak loopt het + zo uit de hand dat deze mensen hun eigen programma's niet + eens meer snappen die ze twee weken eerder hebben + geschreven. (Ik spreek uit ervaring.) + + + S P A G H E T T I + + Denk nou niet meteen dat ik een arrogante zak ben omdat ik + kritiek op andermans programmeerknoeisels heb, want ik geef + van harte toe dat ik ook zo'n prutser ben geweest. Er is + echter eens een moment in mijn leven geweest dat iemand me + op het feit wees dat mijn programma's de vergelijking met + een hoop stront niet overleefden. Vanaf dat moment heb ik al + mijn aandacht gericht op het leren van de schone kunst van + het gestructureerd programmeren. + + Deze teksten die ik over dit inderwerp ga schrijven zijn + niet bedoeld als cursus, omdat dat helemaal geen effect zou + hebben. Dat zou nl. alleen maar betekenen dat ik jullie mijn + programmeerstijl zou opdringen en dat is niet de bedoeling. + Ze zijn meer bedoeld om jullie aan te sporen ook op zoek te + gaan naar een standaardisatie van jullie programma's. Het + enige dat ik kan doen is jullie een aantal tips geven over + wat voor standaardisatie geschikt is en hoe dat in de + praktijk werkt. [Noot van Stefan: die serie artikelen is er + nooit gekomen, daar ga ik dus verandering in brengen!] + + Er zullen ongetwijfeld mensen zijn die al een eigen methode + van werken hebben en die in staat zijn programma's te + schrijven die best voor andere mensen leesbaar zijn, maar ik + neem nu de stelling dat de methode die ik ga bespreken de + beste is. Dit omdat hogere programmeertalen ook allemaal uit + gaan van deze methode, dus als je deze methode al kent op + een moment dat je met een hogere taal geconfronteerd wordt + dan kan dat alleen maar voordeel opleveren. + + De methode van werken die ik (en met mij vele informatici) + gebruiken is niet een strakke methode en dat is maar goed + ook omdat je de denkwijze van mensen maar heel moeizaam kunt + be�nvloeden. Bovendien zou programmeren een hele saaie + bezigheid zijn als iedereen zich aan een absolute + programmeerstandaard hield. + + Goed, ik denk dat het tijd wordt om maar eens te beginnen en + ik hoop dat deze artikelen veel mensen die nu nog een + spaghetti programmeerstijl gebruiken (oftewel een + 'kbenblijdattutwerkt' stijl) zich tot het ware geloof zullen + bekeren. (Waar heb ik dat eerder gehoord?) + + + T O P - D O W N + + De methode die ik altijd gebruik heet de top-down methode en + is uit te leggen met een voorbeeld. Stel je zit in een + wolkenkrabber op de 100ste verdieping. Vanuit die hoge + positie kan je de hele stad overzien, maar nu ga je naar + beneden zodat je steeds minder van het geheel gaat zien, + terwijl de detaillering van het deel dat je nog wel kunt + zien steeds groter wordt. + + De stad in het voorbeeld is het op te lossen probleem. Je + kan het hele probleem van boven overzien, waarbij je alleen + de verschillende deelproblemen die je op moet lossen kunt + overzien. Als je lager komt kan je steeds beter de oplossing + van de verschillende deelproblemen zien die op hun beurt ook + weer uit deelproblemen kunnen bestaan. Op het moment dat de + lift beneden is zijn voor alle deelproblemen oplossingen + gevonden, oftewel het programma is af. Natuurlijk is het + handig af en toe even met de lift omhoog te gaan zodat je + weer helemaal precies weet waar je mee bezig bent. Ook is + het handig om even naar de verschillende deelproblemen kijkt + voordat je met programmeren begint om er achter te komen of + je alle problemen wel op kan lossen. Lukt dit nl. niet dan + ben je dus niet in staat om het programma te schrijven en is + het raadzaam om eerst wat minder hooi op je vork te nemen. + + + D E P R A K T I J K + + Goed, we zullen nu eerst de puur theoretische oplosmethode + bekijken voor machinetaal. + + Bij de top-down methode is het heel handig om modulair te + programmeren. Dat betekent dat je deelproblemen apart oplost + zodat ze in principe ook los van de rest van het programma + werken en dat je ze in andere programma's in kunt bouwen. + Het beste voorbeeld van een modulair geschreven routine is + de BIOS. Deze routines zijn zo standaard dat ze door alle + verschillende programma's gebruikt kunnen worden. Een andere + eigenschap van een modulaire routine is dat informatie die + de ene routine maakt ook door andere routines bruikbaar is. + De BIOS voldoet ook aan deze eis, zo wordt b.v. het huidige + schermnummer op een vaste plaats bewaard. Het blijkt dat het + standaardiseren van eigen routines een zeer taaie klus is en + het is voor de meeste eigen geschreven routines vaak niet + echt belangerijk. De eigenschap dat eigen routines ook los + van de rest van programma kunnen werken en uitwisselbaar + zijn is veel belangerijker. + + Goed, een programmeur is dus blijkbaar iemand die volgens + een vaste methode (in ons geval de top-down methode) en + volgens het principe van modulair programmeren programma's + schrijft. + + Als er mensen onder jullie zijn die later programmeur willen + worden dan kan ik ze aanraden om de bovenstaande alinea goed + te onthouden want deze regel geldt in de praktijk voor alle + programmeertalen die ooit ontworpen zijn sinds de invoering + van de CPU. + + Programma's die volgens de top-down methode zijn geschreven + zijn heel eenvoudig herkenbaar. Ze beginnen nl. vaak met een + lijstje EQU instrukties waarna een hoofdprogramma volgt + waarin de instruktie CALL overheerst. Achter dat + hoofdprogramma staan altijd de routines waar die CALL's + heenspringen en achter deze routines staan dan vaak nog een + lading data's. + + De routines waar de CALLs heenspringen zijn altijd modulair, + maar dat betekent in de praktijk vaak dat ze niet in andere + programma's bruikbaar zijn omdat ze te specifiek bij het + programma horen waar ze voor geschreven zijn. Een voorbeeld + hiervan is b.v. een routine bij een lichtkrant (scroller) + die de plaats van het volgende stukje letter berekend en + zoekt, terwijl een routine die een lijn trekt heel goed + uitwisselbaar is. + + Als je mij gelooft dan moet je nu dus ook geloven dat een + programma dat met de top-down methode geschreven is ook door + andere programmeurs ontcijferd kan worden. Dit is wel waar, + maar het komt niet door de top-down methode want die stelt + eigenlijk niets voor. Nee, het komt door een bijzonder + aangenaam bijverschijnsel dat altijd optreedt als je de + top-down methode gebruikt. Want het programmeren in + spaghetti stijl wordt nl. onmogelijk gemaakt. + + + I T A L I A A N S E K O O K K U N S T + + De spaghetti stijl is de stijl waar de meeste prutsers mee + beginnen. Er wordt konstant heen en weer gesprongen tussen + verschillende routines waardoor het programma wordt + gedegradeerd tot doolhof voor iemand die de werking ervan + moet uitvissen. Bovendien slaan dit soort programma's nogal + snel (en heel heel vaak) vast als er kleine (of grote) + veranderingen in worden aangebracht. Je begrijpt dat het + vinden van bugs een zeer slopende en tijdrovende bezigheid + is (gniffel gniffel). Het enige voordeel dat deze misbaksels + hebben is dat ze inderdaad redelijk kraakvrij zijn, maar + helaas geldt dat ook vaak voor de programmeur. (Ik spreek + trouwens nog steeds uit ervaring.) + + De spaghetti stijl wordt onmogelijk gemaakt omdat je heel + goed op je stack moet letten omdat een routine die met een + CALL wordt aangeroepen met een RET weer terug moet, terwijl + de stack er bij het ingaan van de routine hetzelfde uit moet + zien als bij het terug gaan om hele vreemde errors te + voorkomen. Het is natuurlijk altijd mogelijk om spaghetti te + maken, maar de top-down methode heeft een sterk remmende + werking op deze gang van zaken. + + + Je moet dus een aantal regels gebruiken: + + - Je mag nooit van de ene routine in de andere routine + springen. Wel mag je in de eigen routine naar hartelust de + meest vreemde bokkensprongen maken. Moet je in een routine + een andere aanroepen, dan moet dit met een CALL statement + gebeuren. + + - Als je in een routine iets op de stack zet, dan moet dit + in dezelfde routine weer van de stack gehaald worden. Dus + niet alleen PUSH en POP, maar ook CALL of iets anders. + (Deze regel kan in een hogere programmeertaal niet eens + ontdoken worden.) + + Er blijken uitzonderingen mogelijk op deze regels, maar een + goede programmeur laat zich daar niet door uit het veld + slaan en bedenkt een manier zodat deze regels toch + gehandhaafd blijven. + + + V O O R D E L E N + + - Programma's zijn goed leesbaar en begrijpbaar + - Programma's zijn snel bugvrij te maken en te houden. + - Hoe langer je oefent, des te sneller je in staat zult zijn + om een foutloos programma te schrijven. + - Je maakt een fantastische opstap om aan een hogere + programmeertaal te beginnen. (Overigens is BASIC geen + hogere programmeertaal.) + - Je mag jezelf programmeur noemen + - Je kunt eens lachend op prutsers neerkijken (even + vergetende dat je er zelf ook een bent geweest). + + + N A D E L E N + + - Het is lastig om je alles aan te wennen. + - Tja, eh... Er zijn eigenlijk geen nadelen van belang. + + Goed, dat was het voorlopig. Ik zal zeer zeker een volgende + keer een meer praktische benadering van deze methode geven. + + A A N A L L E P R U T S E R S + + Lig over deze tekst maar eens een nachtje wakker en maak een + besluit of je in de toekomst door wilt gaan met je gepruts, + of dat je bereid bent om iets anders te proberen. + + + Hopelijk heb ik niet al te veel mensen op hun (meestal + uitschuifbare) tenen getrapt, maar ik kan deze mensen + verzekeren dat ze vanzelf zullen struikelen als ze blijven + zweren bij de Italiaanse kookkunst (spaghetti). + + Alex van der Wal + + + (Nu al 1.5 jaar geen prutser meer, alhoewel ik dit jaar het + meeste geleerd heb.) [Nvdr. Klopt niet, omdat deze tekst al + 2 jaar oud is.] diff --git a/sunrise_special/5/HD op write protected.md b/sunrise_special/5/HD op write protected.md new file mode 100644 index 0000000..45c83e8 --- /dev/null +++ b/sunrise_special/5/HD op write protected.md @@ -0,0 +1,21 @@ + H D O P W R I T E P R O T E C T E D + + + Soms is het fijn om je HD op write protected te hebben + staan. Bijvoorbeeld bij het proberen van een of ander + luguber diskje met je harddisk aangesloten. Het op write + protected zetten is op zich niet veel moeite. Alleen even + FORMAT onder MSX-DOS of CALL FORMAT onder BASIC en een paar + instellingen. + + Maar het is lastig als je dat 4 keer in moet typen (voor + elke partitie ��n keer). Een batchfile lijkt de oplossing, + maar dan wordt het vrij traag. Zo kwam Erik Maas al een hele + tijd geleden op het idee om PROTECT.COM te maken. Een + COM-file die even snel de harddisk op write protected zet. + + De source PROTECT.GEN staat ook op disk, zodat je het simpel + kunt aanpassen voor een harddisk met een ander aantal + partities. + + Kasper Souren diff --git a/sunrise_special/5/IO Interface.md b/sunrise_special/5/IO Interface.md new file mode 100644 index 0000000..9ec8d6b --- /dev/null +++ b/sunrise_special/5/IO Interface.md @@ -0,0 +1,292 @@ + I / O I N T E R F A C E + + + + J O Y S T I C K E N T O E T S E N B O R D + + Over het gebruik van joysticks en mouse via I/O poorten is + nog niet veel gepubliceerd, waardoor (nog) vaak gebruik + wordt gemaakt van de "trage" MSX ROM BIOS. Door gebruik te + maken van de I/O poorten kan het uitlezen en vooral het + verwerken van de informatie veel sneller geschieden (tja, + bedenk eens een leuk woord?). + + + P S G P O O R T E N + + Zoals mischien bekend is, wordt de PSG niet alleen gebruikt + voor het generen van geluiden maar ook voor het uitlezen van + informatie voor de joysticks, mouse, trackball, en leespen. + Deze PSG gebruikt twee 8-bit I/O poorten, poort A en B + respectievelijk r#14 en r#15. + + De PSG gebruikt de volgende I/O poorten: + + - &HA0 register poort. Geef hierin op het register dat moet + worden gelezen, of beschreven. + - &HA1 schrijf poort. Hier kan de data in worden geschreven + die naar het register - opgegeven in &HA0 - moet. + - &HA2 lees poort. Na het opgeven van welk register er moet + worden gelezen, zal hier de data in staan. + + + Een overzicht van de (joystick) poorten: + + interface 1 interface 2 + +-------------------+ +-------------------+ + | 1 2 3 4 5 | | 1 2 3 4 5 | + | 6 7 8 9 | | 6 7 8 9 | + +-------------------+ +-------------------+ + + (8) - naar poort B:b4 (8) - naar poort B:b5 + (5) - +5V (5) - +5V + (9) - nul (9) - nul + + De terminals (pennen) 1,2,3,4,5 en 6 van beide poorten + worden samen gevoegd en worden gezonden naar poort A:b0-b5. + + + F U N C T I E V A N D E P O O R T E N + + De twee poorten worden als volgt gebruikt: + + Poort A b7 b6 b5 b4 b3 b2 b1 b0 + r#14 cas x trB trA DR3 DR2 DR1 DR0 + + cas: data input van cassette. + trA: Vuurknop A + trB: Vuurknop B + DRx: Joystick richting. + DR0 = omhoog + DR1 = omlaag + DR2 = links + DR3 = rechts + + Noot: De bits zijn ge�nverteerd, dus 0=aan en 1=uit. + + + Poort B b7 b6 b5 b4 b3 b2 b1 b0 + r#15 ar In 2t8 1t8 0 0 0 0 + + ar: Arabische led. (0=ON) + in: Interface nr. (0=interface 1) + 1t8: Verbonden met pen 8 van interface 1, voor de mouse. + 2t8: Verbonden met pen 8 van interface 2, voor de mouse. + + Noot: Ook hier zijn de bits ge�nverteerd. + + + L E Z E N V A N E E N J O Y S T I C K + + Om joystick 1 te lezen, zullen we eerst b6 van r#15 nul + moeten maken. Let hierbij op dat de andere bits niet worden + verwaarloosd. Na het schrijven van r#15, kan de joystick + status worden uitgelezen. Laat ik dit verduidelijken met een + voorbeeld: + + ; Read Joystick. + ; In: C, joystick nr.(&H00=stick #1, &H40=stick #2) + ; Out: A, joystick status + RD_JOY: DI + LD A,15 + OUT (&HA0),A + IN A,(&HA2) + AND &B10001111 ; interface 1 + OR C + OUT (&HA1),A + LD A,14 + OUT (&HA0),A + IN A,(&HA2) + EI + RET + + Als eerste wordt r#15 gelezen, omdat somige bits moeten + worden bewaard. Door de AND functie zal b6 nul worden, + waardoor interface 1 zal worden gebruikt. Register 'C' is + nul, dus zal b6 ook niet worden gezet (als je joystick 2 wil + lezen, moet b6 van 'C' gezet worden). Hier na wordt de + waarde weer naar de PSG geschreven. Door nu r#14 te lezen, + zal het A register de joystick1 waarden bevatten. + + + P R A K T I S C H G E B R U I K + + Om nu bijvoorbeel in een spel de stick waarde te lezen, kan + er gebruik worden gemaakt van de ROM-BIOS "GTSTCK" (&HD5). + Deze routine doet feitelijk het volgende: + + Kijkt welke stick er moet worden gelezen (opgegeven in 'A' + register). Dat kan zijn: 0, Keyboard 1, Joystick #1 2, + Joystick #2. Stel we willen de waarde van Joystick #1 weten. + De BIOS routine leest eerst de stick waarde uit de PSG + poorten. Vervolgens zal uit een tabel de stickwaarde worden + gelezen. Deze waarden zijn hopelijk wel bekend (1=omhoog, + 2=omhoog/rechts, 3=rechts etc.). Afhankelijk van deze waarde + die wordt terug gegeven, kan in een eigen applicatie naar + een bepaald adres worden gesprongen. Maar zou het niet veel + sneller zijn als we inplaats van de stickwaarde, een Jump + adres terug zouden krijgen. Hierdoor hoeven we niet eerst de + stick waarde te onderzoeken, om daarna naar een label te + springen. + + Als we even verder borduren over zo'n routine zou het ook + wel makelijk kunnen zijn om, in plaats van de stick nummer + op te geven, gewoon alle sticks uit te laten lezen. Met als + prioriteiten: Keyboard, Joystick #1, Joystick #2. + + Als we nu ook nog een tabel pointer adres opgeven, waaruit + de adressen kunnen worden gelezen, dan zouden we een pracht + van een routine hebben. Deze zou niet alleen snel zijn, maar + ook zeer multifunctioneel. Immers we hoeven alleen maar een + tabel adres op te geven, waar in staat waar naar toe moet + worden gesprongen als de corresponderende stick waarde wordt + gelezen. Zo'n routine zal er dan als volgt uit komen te + zien: + + ; Read Stick(s) + ; In: HL= Tabel pointer adres. + ; Out: HL= Jump adres. (0=invallid) + RDSTCK: CALL RDS_KB ; Lees keyboard. + AND &H0F + CP 15 ; KB=0 ? + LD C,0 + CALL Z,RD_JOY ; Ja, dan lees joystick #1 + AND &H0F + CP 15 ; Is deze ook nul ? + LD C,&H40 + CALL Z,RD_JOY ; Lees dan joystick #2 + AND &H0F + LD C,A + LD B,0 + ADD HL,BC + ADD HL,BC + PUSH DE + LD E,(HL) ; adr Laag + INC HL + LD D,(HL) ; adr Hoog + EX DE,HL ; HL=adres + POP DE + RET + ; Read Keyboard cursors. (same as RD_JOY, but now KB) + RDS_KB LD A,8 + CALL RDKMAT ; [RDKMAT] = BIOS &H0141 + RRCA ;>Zorg er voor dat de bits + RRCA ; overeen komen met die van + RRCA ; de joysticks: deel door 8, + SET 3,A ; swap bits 2,3 (L -> R -> L) + BIT 2,A + JP NZ,RSKB.0 + RES 3,A + RSKB.0 SET 2,A + BIT 7,A + RET NZ + RES 2,A + RET + + Bij het lezen van de Cursors wordt rij 8 van het toetsenbord + matrix gelezen, en geconverteerd zodat de bits van de + cursors en joystick het zelfde zijn. De cursors bits hebben + namelijk deze volgorde: (rij 8) + + b7 b6 b5 b4 b3 b2 b1 b0 + r8 RGT DWN UP LFT x x x x + + RGT: Rechts + DWN: Omlaag + UP: Omhoog + LFT: Links + + Ook hier zijn de bits weer omgedraaid, dus 0=AAN en 1=UIT! + + Vergelijk de bits maar een met die van de joystick. Na het + converteren zal de cursor waarde het zelfde zijn als die van + en joystick, zodat we maar een pointer tabel hoeven aan te + maken. De bit-waarden van alle sticks: + + b0: Omhoog + b1: Omlaag + b2: Links + b3: Rechts + + Als een stick-waarde gelijk ik aan 15 (wat dus nul is als de + bits zijn geinverteerd), dan zal een volgende stick worden + gelezen. De pointer tabel zal er als volgt uit moeten zien: + (bevat 16 adressen) + + STCKTB: DB 0, 0, 0, 0, R/D, R/U, R, 0 + DB L/D, L/U, L, 0, L, 0, D, U + + L: Links + R: Rechts + D: Omlaag + U: Omhoog + en combinaties: U/L= Omhoog en Links. + + De waarde die uit de RDSTCK routine komt, is nu een adres. + Als we in onze eigen applicatie een jump routine aanroepen + met het adres in HL, dan zal deze de betreffende routine + aanroepen indien het adres ongelijk is aan nul. Een + voorbeeld van een dergelijke jump-routine: + + JUMPER: LD A,H + OR L + RET Z ; HL=0 + JP (HL) ; Spring naar een adres. De return + ; in die routine keert terug naar + ; waar JUMPER is aangeroepen. + + Met deze routine moet het nu mogelijk wezen om snel (save) + en simpel gebruik te kunnen maken van de cursors en beide + joysticks. + + Nu resten alleen nog de vuurknoppen. Als we net zo'n soort + routine maken als RDSTCK, waarbij ALLE vuurknoppen worden + gelezen (natuurlijk onderscheid makend tussen vuurknoppen A + en B). Als we voor vuurknop 1 de spatiebalk, joystick 1 knop + A en joystick 2 knop A nemen, zal de routine er als volgt + uit komen te zien: + + ; Read Trigger #1 + ; Out: Zerro flag, 0=ON, 1=OFF + RDTRG1: LD A,8 ; Lees spatie + CALL RDKMAT + AND &H01 ; spatie ingedrukt? (bit 0) + RET Z ; Ja! + + LD C,0 ; Joystick #1 + CALL RD_JOY + AND &H10 ; Vuurknop A (bit 4) + RET Z ; Ja! + + LD C,&H40 ; Joystick #2 + CALL RD_JOY + AND &H10 ; Vuurknop A + RET + + Voor vuurknoppen B, kunnen we wat betreft het keyboard de + GRAPH toets gebruiken: + + ; Read Trigger #2 + ; Out: Zerro flag, 0=ON, 1=OFF + RDTRG2: LD A,6 ; Lees GRAPH + CALL RDKMAT + AND &H40 ; ingedrukt? (bit 2) + RET Z ; Ja! + LD C,0 ; Joystick #1 + CALL RD_JOY + AND &H20 ; Vuurknop B (bit 5) + RET Z ; Ja! + LD C,&H40 ; Joystick #2 + CALL RD_JOY + AND &H20 ; Vuurknop B + RET + + De routine is bijna het zelfde als RDTRG1. Het enige + verschil is dat hier de B vuurknop wordt gelezen. + + Het extra voordeel van al deze routines is dat er nu niet + van het ROM-BIOS gebruikt wordt gemaakt. Met deze informatie + moet het mogelijk zijn om de joystick en cursors voledig te + kunnen gebruiken. + + R�man van der Meulen diff --git a/sunrise_special/5/Interrupt mode 2.md b/sunrise_special/5/Interrupt mode 2.md new file mode 100644 index 0000000..470e972 --- /dev/null +++ b/sunrise_special/5/Interrupt mode 2.md @@ -0,0 +1,139 @@ + I N T E R R U P T M O D E 2 + + + De Z80 kent 3 interrupt modes. Het hele operating system van + MSX werkt maar met ��n van deze modes, te weten IM 1 + (Interrupt Mode). Feitelijk is dit een beperking omdat de + andere interrupt modes zeer interessante mogelijkheden + bieden. + + De precieze werking van de verschillende interrupt modes is + nader beschreven in een eerder artikel op Sunrise Special. + Interrupt mode 0 is op MSX niet bruikbaar, IM 1 wordt + normaliter gebruikt en IM 2 is een twijfelgeval. + + In het eerdere artikel heb ik beweerd dat ook IM 2 op MSX + niet bruikbaar is, maar dat is niet helemaal waar. Om het + geheugen eerst wat op te frissen volgt eerst even een korte + uitleg van IM 2. + + + I M 2 + + IM 2 is op Z80 de zgn. 'Vector Interrupt' mode. Dat houdt in + dat er naar verschillende ISR's (Interrupt Service Routine) + gesprongen kan worden na het optreden van een interrupt. Op + Z80 werkt dit als volgt. + + In het geheugen staat een tabel van max. 256 bytes waar + praktisch per twee bytes een 16 bits adres kan staan. Totaal + zijn volgens deze rekening 128 adressen mogelijk. In het I + register van de processor moet nu het HI byte van het + startadres van deze tabel komen. + + &HC000 = vector entry 0 + &HC002 = vector entry 1 + ... + &HC0FE = vector entry 127 + + Het I register moet hier de waarde &HC0 hebben waardoor de + processor het startadres van de tabel weet. + + IM 2 gaat er van uit dat het interrupt genererende apparaat + niet alleen het INT lijntje aktief maakt, maar dat ditzelfde + apparaat (bv. de VDP) ook een getal op de bus zet. In ons + voorbeeld mogen dat dan alleen positieve getallen zijn. Stel + een chip genereert een interrupt en zet de waarde 2 op de + bus. De processor gaat nu de waarde van het I register + combineren met de waarde die op de bus komt tijdens een + interrupt. Daaruit volgt dan een 16 bits waarde (&HC002 in + dit voorbeeld). De processor leest nu het 16 bits getal + vanaf dit gecombineerde adres en springt vervolgens naar het + zojuist gelezen adres. + + Vb: + + &HC000 = (&H8000 = ISR 1) + &HC002 = (&H9000 = ISR 2) + I = &HC0 + Indien chip A een interrupt genereert en de waarde 0 op de + bus zet zal uiteindelijk naar adres &H8000 gesprongen + worden. Indien chip B de waarde 2 op de bus zet zal + uiteindelijk naar adres &H9000 toegesprongen worden. Indien + chip C de waarde 1 op de bus zou zetten zal naar adres &H80 + gesprongen worden (voer voor de pro's). + + Het voordeel van deze methode is dat er geen vertragende + routines meer nodig zijn om er achter te komen van welke + chip de interrupt af komt. Dat wordt allemaal door + hardware geregeld. Het enige waarvoor gezorgd moet worden is + dat indien er verschillende chips zijn die interrupts + genereren deze allen een verschillende waarde op de bus + zetten. + + + I M 2 E N M S X + + IM 2 is op MSX niet expliciet nodig omdat er maar 1 chip is + die een interrupt aan de processor door kan geven, nl. de + VDP. Daar komt nog bij dat de VDP helemaal geen waarde op de + bus zet als deze een interrupt genereert, dus IM 2 lijkt op + MSX nutteloos. + + Vanuit die gedachtengang heb ik destijds beweerd dat IM 2 op + MSX niet mogelijk is, wat niet helemaal waar blijkt te zijn. + Het is op MSX mogelijk om 1 vectorinterrupt te gebruiken + i.p.v. de praktische 128 in het vorige voorbeeld. Op MSX is + de Z80 zelf de enige chip in de computer die een lees of + schrijfaktie op de bus kan beginnen. De CPU is dus de enige + 'Bus Master'. Indien zelfs de Z80 niet op de bus schrijft + zal de waarde op de bus altijd &HFF zijn. De buslijnen zijn + van het 'Pull up' type (open collector uitgang voor de + electrotechneuten) wat dus praktisch neerkomt op de waarde + &HFF. + + Treedt er nu een interrupt op (altijd afkomstig van de VDP) + dan zal de Z80 indien IM 2 aktief is op de bus kijken en de + waarde &HFF zien. Indien het I register de waarde &HC0 heeft + zal dus de 16 bits waarde vanaf adres &HC0FF gelezen worden + waarna naar deze waarde gesprongen wordt. + + Het praktisch nut van dit 'geintje' is dat zo voorkomen kan + worden dat naar adres &H38 gesprongen wordt. We kenden al + een geintje om via &HFD9A te voorkomen dat de hele rimram + die normaal gesproken bij een interrupt uitgevoerd wordt + over te slaan. Een andere methode was het uitschakelen van + de ROM-BIOS waardoor een eigen routine vanaf adres &H38 + gezet kan worden. + + Het uitschakelen van de ROM-BIOS is echter vrij lastig + (vooral in combinatie met de BDOS). Via IM 2 is het nu + echter mogelijk om te voorkomen dat er naar adres &H38 + gesprongen wordt. Daarmee is het dus mogelijk om wel een + kompleet eigen ISR te schrijven, terwijl de ROM-BIOS gewoon + 'aan' kan blijven staan. + + Het is overigens zeer eenvoudig om een klein + testprogrammatje te maken dat met IM 2 werkt. Dat kan er bv. + zo uit zien: + + ORG &HC000 + + RUN: DI + LD HL,&H38 + LD (&HC0FF),HL + LD A,&HC0 + LD I,A + IM 2 + EI + RET + + De werking van dit programma laat zich raden. + + Het is best leuk om eens te stoeien met IM 2. Overigens zijn + de termen IM 0, IM 1 en IM 2 ook assembler instrukties die + als zodanig letterlijk gebruikt kunnen worden. Let wel even + op dat je na afhandeling van een ISR de interrupts weer aan + zet. + + Alex van der Wal diff --git a/sunrise_special/5/MIDI een taal in beweging.md b/sunrise_special/5/MIDI een taal in beweging.md new file mode 100644 index 0000000..50c3160 --- /dev/null +++ b/sunrise_special/5/MIDI een taal in beweging.md @@ -0,0 +1,463 @@ + M I D I : E E N T A A L I N B E W E G I N G + + + MSX is in de ban van MIDI. Alweer heel wat programma's zijn + intussen op de markt verschenen, welke gebruik maken van die + rare ronde aansluitingen, die zoveel lijken op de aloude + audio-aansluitingen. Maar wat is MIDI nu eigenlijk? Dat deze + vraag niet zo gemakkelijk te beantwoorden is als ze op het + eerste gezicht lijkt, wil ik in dit verhaal duidelijk maken. + + MIDI is namelijk heel wat meer dan een methode om data te + sturen naar een keyboard, module of synthesizer. Hoevelen + van u wisten bijvoorbeeld dat MIDI ook bedoeld is om special + effects zoals vuurwerk en rookmachines e.d. aan te sturen? + Om dat allemaal te kunnen is MIDI in eerste instantie + weliswaar niet ontwikkeld, maar is ze wel uitgegroeid. MIDI + is een volwaardige taal geworden. Compleet met grammatica en + vocabulaire. Zelfs compleet met de bij elke taal horende + uitzonderingen op de regels. + + En zoals bij elke taal is het ook bij MIDI noodzakelijk om + de grammatica te leren vooraleer men de taal kan spreken. + Gebeurt dit niet en ga je proberen de taal te spreken + voordat je de grammatica kent, dan zal je instrument je wel + VERSTAAN maar BEGRIJPEN is een andere zaak. Misschien + herinneren enkelen van u nog het lachwekkende Duits van de + Belgische keeper Jean-Marie Pfaff, toen-ie in Duitsland bij + een Duitse ploeg voetbalde. Dat ging zoiets als volgt: + + "Ja, die penalty. Ich zag al an sein anlaufen, dattie der + bal rechts van mij wollte gaan schiessen, dus war het f�r + mich auch nicht zo moeilijk die bal te stopfen..." + + Dat dit geen Duits is ziet elke Nederlander. Maar dat toch + zo ongeveer elke Duitser begreep wat Jean-Marie wilde zeggen + ligt toch minder voor de hand. Voor MIDI geldt ongeveer + hetzelfde. Zolang de foutjes tegen de grammatica nog niet t� + erg zijn, zal elk instrument begrijpen wat u bedoelt, maar + wilt u een echt 'gesprek' met uw instrument aangaan, dan + zult u toch de grammatica (en de vocabulaire van uw + instrument) enigszins onder de knie moeten hebben. Bovendien + is de vocabulaire niet bij elk instrument gelijk! Evenals + niet elk persoon het woord 'ambivalentie' kent [Nvdr. Eh?], + terwijl het toch een goed Nederlands woord is, zo kent ook + niet ieder instrument alle MIDI-codes. Kijk dus niet al te + gek op, wanneer uw instrument niet begrijpt wat u zegt, + terwijl u uzelf netjes aan de MIDI-regels houdt... + + + M I D I A L S T A A L + + Tot zover de (lange) inleiding. Want als we het hebben over + de grammatica van MIDI, dan hoort daar ook een uitleg bij, + nietwaar? Want, hoe 'spreek' je nu foutloos MIDI? + + Ten eerste bestaat MIDI alleen maar uit getallen. En wel de + getallen 0 t/m 255. De hele MIDI-vocabulaire bestaat dus uit + precies 256 'woorden'. + + Ten tweede dien je een juiste zinsopbouw te volgen. Net + zoals bij een echte taal. Laten we eens het volgende + Nederlandse zinnetje bekijken: + + Ik ga fietsen + + De woorden "ga" en "fietsen" zeggen iets over de "ik". Ze + verschaffen als het ware data bij het woordje "ik". Zonder + die data betekent het zinnetje niets. Dit geldt voor MIDI in + exact dezelfde mate. Elke MIDI-zin dient te beginnen met die + informatie, waarover je iets wilt zeggen. In MIDI-termen: + Elke zin dient te beginnen met een status-byte gevolgd door + een aantal databytes. Maar hoe herken je nu een statusbyte? + Dat hebben de heren MIDI-uitvinders iets intelligenter + gedaan dan de heren Nederlandse-taal-uitvinders. In de + Nederlandse taal is alleen door ervaring of studeren te + leren welke woorden nu statuswoorden zijn. In MIDI hebben ze + het simpeler gemaakt: Elk getal dat groter is dan 127 is een + statusbyte. Is het getal dus 127 of kleiner, dan betreft het + een databyte. + + Elke MIDI-zin dient dus te beginnen met een getal dat groter + is dan 127. Deze statusbytes vertellen het instrument wat + het moet gaan doen. De databytes daarna vertellen HOE het te + doen. + + De statusbytes zijn bovendien nog ingedeeld in 8 groepjes + van 16 getallen, corresponderend met het aantal MIDI-kanalen + dat MIDI kan aansturen. Dit is eenvoudiger zichtbaar te + maken wanneer de getallen hexadecimaal worden weergegeven: + Een statusbyte begint dan namelijk met een getal tussen 8 en + F en eindigt met een getal tussen 0 en F. Dit laatste getal + geeft het MIDI-kanaal aan (0=kanaal 1 t/m F=kanaal 16). + + Het eerste getal vertelt MIDI wat te gaan doen en welke + databytes te verwachten. Net als in een gewone taal: Na een + woordje 'je' verwacht je een werkwoordsvorm behorend bij + 'je', ook al zou deze werkwoordsvorm er hetzelfde uitzien + als een andere werkwoordsvorm. Bij een zinnetje als 'Je gaat + fietsen' is het tweede woord exact gelijk aan het tweede + woord uit de zin 'Hij gaat fietsen', terwijl de betekenis + (puur grammaticaal gezien) niet gelijk is. De eerste keer is + het een werkwoordsvorm behorend bij 'je', de tweede keer een + werkwoordsvorm behorend bij 'hij'. Maak van beide woordjes + 'gaat' maar eens een verbuiging van het werkwoord 'zijn'. + Het eerste 'gaat' wordt 'bent' het tweede 'gaat' 'is'. Voor + MIDI geldt dit ook. De databytes zijn voor alle statusbytes + gelijk van vorm (nl. 0 t/m 127) maar verschillen in + betekenis afhankelijk van het (hexadecimale) getal waarmee + een statusbyte begint. + + + N O T E O F F + + Als een statusbyte begint met een 8h (dit zijn dus de + statusbytes 80h t/m 8Fh) betekent dit voor MIDI dat er een + toon UITgezet moet worden. Er behoren nu twee databytes te + volgen, die aangeven welke noot uitgezet dient te worden en + hoe snel de toon moet uitsterven. Deze tweede databyte wordt + bij lange na niet door alle instrumenten begrepen, maar + weglaten is NIET toegestaan. Evenmin als de zin 'Ik voel mij + ambivalent' duidelijk wordt als het woord 'ambivalent' wordt + weggelaten, is het voor MIDI duidelijk wanneer de tweede + databyte wordt weggelaten. Het grote verschil is dat MIDI + handelt naar wat er WEL begrepen wordt en dus de toon uitzet + met een gemiddelde snelheid (terwijl misschien bedoeld was + om de toon extra snel uit te zetten). + + + N O T E O N + + De statusbytes beginnend met een 9h (dus 90h t/m 9Fh) laten + een toon AANzetten. Wederom worden er door MIDI twee + databytes verlangd, waarbij de eerste aangeeft welke noot + aan te zetten en de tweede de velocity (i.e. de hardheid + waarmee de toon aangeslagen dient te worden). Dit statusbyte + behoort tot de standaard-vocabulaire van elk instrument; + ieder instrument begrijpt het. + + Er geldt ook nog een uitzondering bij deze statusbyte, die + eigenlijk meer regel dan uitzondering is. Wanneer een noot + aangezet wordt met een velocity (dus tweede databyte) van 0, + wat dus feitelijk betekent dat een noot wordt aangezet + ZONDER deze aan te slaan, wordt daarmee een eerder + aangezette noot UITgezet! Deze uitzondering is bij alle + instrumenten bekend en wordt zelfs meer gebruikt dan de + offici�le methode van uitzetten. + + Wanneer uw instrument u dus vertelt een noot aan te zetten + met een velocity van 0, bedoelt hij niets meer dan een + vorige noot (met uiteraard eenzelfde eerste databyte) UIT te + zetten. Tja, MIDI is zelfs qua uitzonderingen een + volwaardige taal! + + + P O L Y P H O N I C K E Y P R E S S U R E + + Begint een statusbyte met een Ah, dan wordt daarmee de zgn. + polyfonische toetsdruk (in Engels polyphonic keypressure) + geregeld. Een moeilijk woord en een even moeilijk begrip, + waarvoor we bij de uitleg zelfs naar niet-elektronische + instrumenten moeten kijken. Eenieder, die ooit een (goede) + uitvoering van het muziekstuk 'Il Silenzio' heeft mogen + aanhoren, heeft kunnen horen dat de trompet de lange noten + aan het einde laat 'trillen'. [Nvdr. De functie MOD van + MoonBlaster doet hetzelfde.] Nu wilden de muziekmakers, dat + dergelijke effecten ook via MIDI aan te sturen waren. De + MIDI-makers, niet al te beroerd, voerden dus de polyfonische + toetsdruk in. Wanneer bij een (duurder) instrument na het + aanslaan van een toets nog eens extra op de toets gedrukt + wordt (bij de instrumenten spreekt men van aftertouch), kan + men een extra effect aanroepen. Dit extra effect is meestal + het trillen van de toon, maar in tegenstelling tot wat veel + mensen menen, is dit NIET standaard! Er bestaan ook wel + instrumenten, die de toonKLANK veranderen wanneer er + 'door'gedrukt wordt, bijvoorbeeld sommige duurdere + synthesizers. + + In MIDI werkt de polyfonische toetsdruk alsvolgt: Eerst + uiteraard de statusbyte (A0h t/m AFh) gevolgd door twee + databytes. De eerste databyte geeft aan welke noot het + effect krijgt, de tweede databyte de hoeveelheid effect. + + PAS OP: De noot hoeft niet aan te staan! Een leuk resultaat + is te krijgen door een bepaalde noot dit effect te geven + ZONDER dat deze eerst is aangezet. Elke volgende keer dat + deze noot wordt aangezet krijgt de noot nu automatisch dit + effect. Op deze manier kun je bijvoorbeeld een valse piano + imiteren. Die toets die vals moet klinken geef je polyfonic + keypressure en elke volgende keer dat deze toets wordt + aangeslagen, zal het geluid 'gek' doen (het nut van deze + truuk is vrij beperkt, maar ach, het is er ��n...). + + + C O N T R O L C H A N G E + + Begint een statusbyte met een Bh (dus het hexadecimale getal + B, voor alle duidelijkheid...) dan betreft het een Control + change. Dit statusbyte is zonder twijfel ��n der + krachtigsten van MIDI. Alle effecten, die niet een eigen + statusbyte hebben, maar wel door verschillende instrumenten + moeten worden begrepen, hebben hier hun basis gevonden. + + De Control change is een lijst van effecten (in Engels: + Controls), die gebruikt kunnen worden om uw conversatie met + uw instrument levendig te maken. De twee databytes die + het statusbyte (dus B0h t/m BFh) volgen geven + achtereenvolgens het soort effect en de 'zwaarte' van dat + effect aan. Daar deze MIDI-boodschap (in MIDI-jargon + MIDI-event genoemd) zo enorm krachtig is, ben ik van zins in + een volgend artikel hierop verder in te gaan. Voor nu kan ik + dus alleen maar zeggen: Als uw MIDI-kennis nog nul is, blijf + dan in 's hemelsnaam van deze boodschap af. De kans dat uw + keyboard iets verstaat, dat u absoluut niet wilt, is + huizenhoog aanwezig. + + + P R O G R A M C H A N G E + + Hier belanden we op de grens van de grammatica en steken we + de brug over naar de vocabulaire. Maar eerst nog even de + grammatica: Het statusbyte (C0h t/m CFh) wordt gevolgd door + slechts ��n databyte. Dit databyte is het MIDI-equivalent + van de vocabulaire. Met dit databyte geef je je keyboard + namelijk te kennen WAT voor geluid deze dient te maken. + + Maar pas op! Tot voor kort had elke producent (en vaak ook + elk instrument) zijn eigen vocabulaire. Dit was zo ontstaan + omdat van oorsprong de program change bedoeld was om + veranderingen aan te brengen in het geluid van synthesizers + zonder geheugen. Toen echter de instrumentmakers de + beschikking kregen over geheugen, zodat een hoeveelheid + standaard-geluiden vooraf al in het instrument opgeslagen + konden worden, werd dit MIDI-event meer en meer gebruikt om + een geluid (afhankelijk van producent patch, programma, + timbre of preset genoemd) te kiezen. + + Maar daar iedere producent zijn eigen voorkeur had voor + geluiden, was de lijst met geluiden ook op ieder instrument + anders. Een standaard was op dit gebied dus (tot voor kort) + ver te zoeken. De situatie was vergelijkbaar met talen, die + wel dezelfde grammatica kenden (dus zinsopbouw), maar heel + andere woorden gebruikten. + + Echter zoals al twee keer kort opgemerkt, is deze toren van + Babel langzaam maar zeker aan het verdwijnen. Een aantal + jaren geleden kwamen de grootste producenten van + instrumenten namelijk overeen om in het vervolg elke waarde + van het databyte eenzelfde instrument te laten selecteren. + Dit betekent geenszins, zoals zo velen menen, dat nu ook + alle keyboards van willekeurig welke producent hetzelfde + KLINKEN! Het betekent alleen dat wanneer je als databyte een + 0 geeft alle instrumenten voortaan een piano-klank laten + horen. Het verschil in klankopwekking is niet veranderd, + zodat een piano op een Yamaha-instrument nog steeds heel + anders (beter...?) klinkt dan op een Casio. Deze standaard + wordt de GM-standaard genoemd, wat staat voor GENERAL MIDI. + + Voor Roland ging deze standaardisatie nog lang niet ver + genoeg en daarom voerden zij de GS-standaard in. Een + GS-instrument is 'upwards compatibel' met een GM-instrument, + net zoals bij de MSX-systemen het MSX2-systeem upwards + compatibel was met het MSX1-systeem (met die uitzondering, + dat bij MIDI de compatibiliteit WEL 100% is) en een minister + wel begrijpt wat een bouwvakker zegt, maar zelden + omgekeerd... + + Op deze twee systemen kom ik een volgende keer terug, daar + dit een bron is van veel, heel veel misverstanden! + + + C H A N N E L P R E S S U R E + + Een statusbyte beginnend met een Dh regelt de channel + pressure, een eenvoudig alternatief voor de polyphonic + keypressure. Toen MIDI ontstond dacht men voor aftertouch + (zie polyphonic keypressure) twee alternatieven nodig te + hebben; een duur (de polyphonic keypressure) en een goedkoop + (de channel pressure). Dit vanwege het feit dat + drukreceptoren onder toetsen een dure aangelegenheid was (en + is!) en dus niet alle producenten �lke toets een eigen + receptor wilden geven. Helaas is het momenteel zo, dat de + polyphonische aftertouch in enorm weinig instrumenten + ingebouwd is en praktisch alle producenten voor de goedkope + variant hebben gekozen. + + Wat MIDI-betreft is het verschil tussen de polyphonic + keypressure en de channel pressure opvallend klein, nl. ��n + databyte. Waar de polyphonic keypressure twee databytes (��n + voor noot en ��n voor hoeveelheid) kent, kent de channel + pressure maar ��n databyte, nl. de hoeveelheid. Het effect + geldt daarna voor alle toetsen (of noten op hetzelfde + MIDI-kanaal, vandaar de naam 'channel pressure' dat + 'kanaaldruk' betekent). Voor de compleetheid dien ik nog op + te merken, dat de polyphonic keypressure door maar weinig + instrumenten wordt begrepen (m.u.v. de GS-instrumenten, waar + het standaard is dat ze polyphonic keypressure kunnen + ontvangen, maar - tot nu toe - geen enkele het uitzendt). + + + - Deel 2 van deze tekst kunt u in het submenu vinden - + + + + + - Deel 1 van deze tekst kunt u in het submenu vinden - + + + P I T C H B E N D C H A N G E + + Nu word ik melancholiek. De Pitch-bender... Wat mij betreft + HET effect, dat de mooiste resultaten kan hebben, maar + tegelijkertijd een liedje volledig kan afbreken. Mensen die + ECHT goed met pitch bend kunnen werken, zijn zeldzaam. Maar + vooruit, niet gedroomd, uitleggen! De pitch bend change + heeft als statusbyte de getallen E0h t/m EFh (dus beginnend + met een Eh). Na dit statusbyte dienen twee databytes te + volgen. De eerste voor de fijnafstemming (LSB) en de tweede + voor de grofafstemming (MSB). Eigenlijk dienen beide + databytes als ��n 14-bits getal gezien te worden, waarbij + het tweede databyte voorop staat. Het bereik is in dit geval + dan ook niet van 0 t/m 127, maar van -8192 t/m +8191! Het + nulpunt ligt bij 64 en 0 (dus eerste databyte 64, en tweede + databyte 0). + + Het resultaat van deze MIDI-boodschap is alles behalve + standaard! Bij Yamaha bijvoorbeeld doet een volledige + uitslag (beide databytes 127) de toon een vol oktaaf + verhogen, terwijl bij Roland slechts 2 halve tonen! Hierin + komt bij de GM-standaard geen verbetering, maar bij de + GS-standaard van Roland wel. Bij de GS-standaard is het + namelijk mogelijk via de control changes genaamd NRPN (Non + Registered Parameter Number) de 'Pitch bend sensitivity' (in + Nederlands de 'gevoeligheid van de pitch bender (sorry, geen + Nederlands alternatief voorhanden)' genaamd) te veranderen + van 0 halve noten tot 24 halve noten (= twee oktaven). De + uitleg ziet u terug in het artikel over GS/GM, de + MIDI-getallen geef ik u hier, zodat diegenen die een + GS-instrument bezitten kunnen gaan experimenteren. + + PAS OP: c = het gewenste MIDI-kanaal (standaard staat elke + upper-part van een GS-instrument op kanaal 4, dus c=3) en x + is de hoeveelheid halve noten, die met de pitch bend + maximaal wordt veranderd: + + Bc 101 0 Bc 100 0 Bc 6 x + + De statusbytes (steeds Bc) zijn hexadecimaal! Wilt u deze + code bijvoorbeeld met behulp van een Music Module naar uw + keyboard sturen op kanaal 4, dan laadt u onderstaand + programma (MIDI.BAS) in waarbij u op de plaats van de c het + gewenste MIDI-kanaal invult en op de plaats van de x het + aantal halve noten: + + 10 out 0,3 : out 0,21 ' = initialisatie MIDI van de MusMod + 20 out 1,&HBc : out 1,101 : out 1,0 + 30 out 1,&HBc : out 1,100 : out 1,0 + 40 out 1,&HBc : out 1,6 : out 1,x + + Gaat u ooit zelf met behulp van MIDI muziek maken en in uw + muziekstuk met pitch bend werken, gebruik dan ALTIJD de + pitch bend sensitivity (ook al herkent uw instrument deze + niet) en vergeet niet aan het eind van uw liedje de pitch + bend sensitivity ALTIJD weer terug te zetten op 2 (dit geldt + trouwens voor alle veranderingen die u in uw muziekstuk + maakt: zet ze aan het eind weer terug)! + + + S Y S T E M M E S S A G E S + + De system messages hebben als overeenkomst dat ze allen + beginnen met een Fh en geen databytes nodig hebben. Voor het + overige zijn deze statusbytes het zwarte schaap van de + MIDI-familie: Ze zijn de uitzondering op zo ongeveer elke + MIDI-regel: + + Het tweede (en uiteraard tevens laatste) getal van de + statusbytes heeft GEEN betrekking op MIDI-kanalen. De system + messages hebben altijd betrekking op het hele instrument. + + De system real time messages mogen NOOIT in een muziekstuk + worden verwerkt en zijn louter bedoeld om de communicatie + tussen instrumenten te bevorderen. + + Voor meer informatie verwijs ik u naar een volgend artikel, + daar over dit onderwerp hele boeken zijn volgeschreven! + + + R U N N I N G S T A T U S + + Dan tot slot nog een opmerking over de zgn. running status. + Net zoals in onze taal bij een opsomming datgene waar iets + over gezegd wordt mag worden weggelaten, mag dit ook bij + MIDI. Een voorbeeld: + + 'De fiets is groen, rijdt prettig, heeft een stalen frame.' + is hetzelfde als: 'De fiets is groen, de fiets rijdt + prettig, de fiets heeft een stalen frame.' + + In MIDI mag dit ook. In plaats van steeds dezelfde + statusbyte te moeten herhalen, hoeft deze slechts ��n keer + (in het begin uiteraard; een MIDI-zin dient nu eenmaal met + een statusbyte te beginnen) genoemd te worden. Mocht u dus + ooit denken bij een conversatie met uw instrument 'Tjonge, + wat gebruikt-ie toch veel databytes', dan is uw instrument + dus bezig met een opsomming en dient u elke keer het + statusbyte erbij te denken. + + Van belang is dus ook het aantal databytes dat normaliter op + een gegeven statusbyte volgt: + + C0h 1 2 3 4 5 6 7 8 9 10 + + betreft 10 MIDI-boodschappen, terwijl + + B0h 1 2 3 4 5 6 7 8 9 10 + + er slechts 5 betreffen! Mocht u dit niet meteen begrijpen, + denkt u er dan aan dat C0h slechts ��n databyte behoeft en + B0h twee! + + + T O T S L O T + + In dit artikel heb ik geenszins beoogd volledig te zijn. + Daarvoor is dit artikel ook in eerste instantie niet + bedoeld. Ik heb alleen maar een basis willen geven om verder + te gaan met MIDI en u er op attent willen maken, dat MIDI + een TAAL is en ook als zodanig behandeld zou behoren te + worden. En net zoals niet elk mens zal begrijpen wat ik hier + schrijf, zal ook niet elk instrument hetzelfde begrijpen van + een MIDI-boodschap. Dat hoort nu eenmaal bij MIDI en is + eigenlijk ook het grootste voordeel van MIDI. + + Daarom blijf ik altijd weer sceptisch staan tegenover het + gebruik van zgn. drivers om alle instrumenten hetzelfde te + laten begrijpen. Naast het feit dat u ten eerste uw + instrument te kort doet (elk instrument heeft zijn + specifieke voordelen, die niet met drivers te ondersteunen + zijn) is het ten tweede onmogelijk om echt alle instrumenten + hetzelfde te laten begrijpen. + + Als voorbeeld voor deze stelling wijs ik alleen maar naar + het pitch bend probleem, zoals ik dat behandeld heb bij het + verhaal over de pitch bend change. Het is toch ook niet + mogelijk om elk mens over de hele wereld dezelfde taal te + laten spreken! En mocht dit ooit tot de mogelijkheden gaan + behoren, dan zullen er direct weer per streek verschillen + ontstaan. In Nederland hebben we talloze woorden om neerslag + aan te duiden (regen, motregen, hagel, sneeuw, stortbui + enz.), terwijl in de woestijn aan dergelijke begrippen + totaal geen behoefte is! Daar hebben ze weer veel meer + behoefte aan woorden die bruin aangeven... + + Mocht u naar aanleiding van dit artikel nog vragen hebben + over MIDI, dan verwijs ik u graag naar een boek dat + geschreven is door Christian Braut, getiteld "Het complete + MIDIboek - Theorie en praktijk" en wordt uitgegeven door + Sybex. Loop eens binnen bij uw plaatselijke bibliotheek en + blader het eens door of ga eens kijken bij uw boekhandel, + waarbij ik eerlijkheidshalve wel dien op te merken dat het + boek niet goedkoop is! + + Ruud van Gestel diff --git a/sunrise_special/5/Make and change directory.md b/sunrise_special/5/Make and change directory.md new file mode 100644 index 0000000..3df5d44 --- /dev/null +++ b/sunrise_special/5/Make and change directory.md @@ -0,0 +1,34 @@ + M A K E A N D C H A N G E D I R E C T O R Y + + + Het programma MCD.COM is gemaakt om de volgende combinatie + te vereenvoudigen: + + MD \UTILS\INPAK + CD \UTILS\INPAK + + Met MCD wordt dit dan: + + MCD \UTILS\INPAK + + De subdirectory INPAK wordt gemaakt in de directory \UTILS + en de huidige directory wordt ingesteld op \UTILS\INPAK. + + + B A T C H F I L E + + De programmeur van MCD.COM heeft echter niet gedacht aan de + mogelijkheid van een batchfile. De volgende twee regels + hebben immmers hetzelfde effect als de COM-file: + + MD %1 + CD %1 + + En als je deze 2 regels invoert in een batchfile genaamd + MCD.BAT, is de werking precies hetzelfde, op ��n ding na: de + mogelijkheid om de directory meteen hidden te maken. + + By the way, MCD.COM is gemaakt door Fokke Post en zit in de + file MCD.PMA, die op deze disk staat. + + Kasper Souren diff --git a/sunrise_special/5/Memman Bugje.md b/sunrise_special/5/Memman Bugje.md new file mode 100644 index 0000000..076ff36 --- /dev/null +++ b/sunrise_special/5/Memman Bugje.md @@ -0,0 +1,186 @@ + + B U G J E I N M E M M A N + + + Deze tekst heb ik gedownload uit BBS Roefsoft. Omdat ik + aanneem dat dit ook interessant is om te weten voor + niet-MST'ers, plaats ik hem. Noot: de tekst is als brief + gericht aan het MST. + + Kasper Souren + + + Geachte programmeurs, + + Bij het maken van TSR's ben ik op een vreemd probleem + gestuit. Misschien ligt het aan mij, maar daar ben ik + ondanks dat ik mijn .GEN file flink heb doorzocht, niet + zeker van. + + Ik krijg ik te maken met vastlopers als ik mijn TSR of + ScrFade dubbel probeer te laden. Misschien lopen ook andere + TSR's vast, ik heb alleen bij deze twee dit opgemerkt. + Uiteraard kijken deze TSR's of ze zelf al zijn + ge�nstalleerd. + + + G E D R A G V A N M I D I X + + MIDIX (mijn TSR) is een TSR die 50 keer per seconde het + Philips-keyboard afscant, omzet naar MIDI data (er kunnen + verschillende "zones" worden gedefineerd), en deze naar + MIDI-out stuurt (nog niet gebufferd). Alle MIDI-IN data + wordt in een ISR (Interrupt service routine) gebufferd, en + deze buffer 50x per seconde door de TSR geleegd. De data + wordt multitimbraal over de 9 Module-kanalen gespeeld. E�n + MIDI-kanaal wordt gebruikt voor drumsamples. + + Overgens werkt de TSR prima, het reloceren en afbuigen in + DOS werkt nu perfekt, alleen wilde ik (in de toekomst dus) + als er dubbel ge�nitialiseerd werd, checken of de oude MIDIX + onder DOS was ge�nitialiseerd, en zo niet, de DOS-interrupt + alsnog goed afbuigen. De adressen in de heap kunnen dan via + een TSRCall naar de oude MIDIX worden opgevraagd. Maar dat + kan nu dus niet. + + + W A N N E E R L O P E N Z E V A S T + + ScrFade en MIDIX lopen allebij vast als ze voor de tweede + keer wordt geinstalleerd, en MIDIX.TSR reeds was geladen. + Overgens heb ik ook eens een redirection error met wat + vreemde tekens gezien nadat ik in BASIC MIDIX WEL twee keer + heb kunnen laden, het kan dus zijn dat ik of MemMan ergens + in het geheugen heeft zitten knoeien, terwijl hij daar geen + recht had. Overgens gebruikte ik MemMan 2.31 en 2.42 (uit + Waterland), DOS 2.22 van MK, en een 1024 kB Memmory mapper + in slot 1, op een VG 8235/00, niet dat wat uitmaakte, want + ook onder MSX-DOS 1 zonder MemMapper, ging het dubbel laden + fout. + + + S Y M P T O N E N + + ScrFade: Laat in een gruwlijk tempo de kleuren wisselen. + Beeld niet om aan te zien, TV lijkt kapot. + Midix: Laat een vreemd gekraak uit de module komen, hier heb + geen verklaring voor. + + Dit duidt er volgens mij op dat de interrupt continue wordt + aangeroepen, TsrMan staat continue te racen. Eigenlijk zou + dan ScrFade in no-time de tijdslimiet gehaald hebben, en dan + het scherm zwart moeten HOUDEN, toch? + + Mijn intialisatie routine ziet er zo uit: + + Init: + ld b,GetMemManEnt ;Ask for MemMan entry + ld de,256*'M' + Info ;Call the MemMan info + ; function + call ExtBio ;Through the ExtBio hook + ld (MemManEntry+1),hl ;Save the MemMan entry + ; address + ; + ld hl,TTsrName ;Pointer to TSR name-string + MemMan GetTsrID ;See if this TSR already + ; exists + jp nc,InitDouble ; Yes, => Double installed + ; error + + .comment / + Initialisatie routine die Heap-ruimte aanvraagt, een stukje + in de de initialisatieroutine aanpast, naar de Heap LDIRt, + FD9Ah afbuigt, en, indien na het bekijken van 00038h, + bepaalt of de TSR vanuit een DOS-omgeving werd geladen. Zo + ja, wordt de JP instructie waarnaar 0038h Jumpt, afgebogen + naar een ISR, die ook in de heap staat. / + + ; einde initalisatie + ld de,OK etc + ld a,2 + ret + ; + InitDouble: + ld de,TDouble + ld a,3 + ret + ; + TDouble: + db "You're not under MSX-DOS, I can't refresh " + db "DOS-MIDI interrupt routine." + dw CrLf + db "Under basic, MIDI-interrupts are almost always " + db "fast enough." + dw CrLf + TTsrName: TsrName + db " was already installed. Old MIDIX still exists." + dw CrLf + db 0 + + Dit zou bij een dubbele installatie probleemloos moeten + werken. Vreemd is dat ik na het eerste keer laden van + MemMan, probleemloos iedere willekeurige TSR kan laden, tot + een Segment full error volgt. + + + M O E I L I J K D O E N I K D E H E A P + + Op een MIDI-int moet de computer elke 1200 cycli (3.58 MHz + Z80) kunnen reageren. Inschakelen van een TSR-segment zal + dan te lang duren, dus heb ik in de Heap een stukje + code+buffer gereloceerd. Als er te weinig Heap-ruimte is, + wordt de buffer automatisch kleiner gemaakt. + + Onder DOS haal ik deze snelheid nog steeds niet, omdat DOS + altijd de BIOS eerst aanschakelt, voordat hij 00038h + aanroept. Hiervoor heb ik de DOS-interrupt JP instructie in + page 3 omgebogen naar mijn routine in de heap, waar nu + uiteraard het een en ander gePUSHt moet worden. Nadat + vastgesteld is dat het een MIDI interrupt is, wordt deze + afgehandeld, en zonder pardon weer EI en RET gegeven, dit om + de VDP-interrupt in het BIOS te vermijden. Mocht er een + MIDI- en VDP-interrupt tegelijk plaatsvinden, dan komt de + VDP vlak na EI RET met een interrupt voor de VDP, waarna + MIDIX hem gewoon via het BIOS laat lopen. + + + I D E E + + Misschien kunnen jullie in MemMan ook dit soort hooks + implementeren, voor snelle RS232- en modem-buffers. Een + nadeel dat ik nu heb, is dat ik in een Kill-routine + programma's die na mij ge�nstalleerd zijn en ook op mijn + manier te werk zijn gegaan, mijn Heap-ruimte niet mag + teruggeven, omdat zij er zonder pardon mijn heapruimte als + trampoline gebruiken. En ik kan er zeer moeilijk + achterkomen, waar zij zich afzetten om bovenop mijn heap te + springen... + + Misschien kan ik een FASTINT.TSR maken, wat dan een + aanvulling op MemMan is. FastInt zou ook in Mst TsrUtils of + worden ingebakken. Deze zou dan de Fast-Interrupt routines + kunnen beheren, aankoppelen en afkoppelen, als ze even niet + nodig zijn. Misschien kan hij ook helpen hij het reloceren + van routines in de heap en aanvragen van bufferruimte. (Oh + ja, is een TSR nou een Hij of een Zij? [Nvdr. Als het niet + bekend is, is het een Hij!] + + Ook zouden parameters bij TL, een teruggeef-tekstje bij TK, + ROMs als segment-code, een Memory-in-bytes-manager voor + nauwkeuriger geheugenbeheer (Pop-up database, scherminhoud + opslag) en een debugging-tool voor TSR's handig zijn. Een + functie voor het opvragen van het segment van een TSR zou + hierbij ook wonderen doen. + + Helaas werkt MSX-Debugger v2.0 (prachtig...) helaas niet zo + makkelijk met MemMan. Heb ik eindelijk via een TsrCall en + GetCurSeg het Segment-no van mijn TSR, voer een USE1 uit, + luistert MSXDEBUG niet meer... Ook een breakpoint in een + ongebruikte hook zetten, die ik aanroep vanuit mijn TSR, + werkt niet... + + Veel geluk/succes/(nog prettige feestdagen? of zijn die al + geweest?) met jullie prachtige MemMan project, van jullie + lastige beller, + + Mark-Jan Bastian diff --git a/sunrise_special/5/Picture packer.md b/sunrise_special/5/Picture packer.md new file mode 100644 index 0000000..e00891f --- /dev/null +++ b/sunrise_special/5/Picture packer.md @@ -0,0 +1,104 @@ + P I C T U R E P A C K E R + + + Vorige keer was er iets behoorlijk mis gegaan met de picture + packer. Op SRS#4 stond namelijk een verouderde versie van + het programma, zodat sommige dingen die ik in de handleiding + had vermeld niet werkten, omdat ze niet in het programma + waren opgenomen! + + Op deze disk vindt u - hoop ik - de goede en iets snellere + versie van het programma. Dat betekent wel, dat uw plaatje + gepackt met de oude versie niet meer kan worden bekeken met + de nieuwe. Maar ik vond dat de voordelen van deze nieuwe + versie groot genoeg waren. + + + D E B E D I E N I N G + + Deze tekst stond ook op SRS#3, maar goed. Eerst dient + KUN-BASIC ingeladen te worden. (Via DOS of met BLOAD, dat + ligt aan uw versie. Mensen met KUN-BASIC ingebouwd, tikken + invoudigweg CALL BC.) [Nvdr. Of gewoon _BC of helemaal niks + voor mensen die KUN-BASIC in ROM hebben zitten.] + + Om een plaatje te packen start u vervolgens PICPACKR.BAS op. + Het programma vraagt om de te packen filenaam. Als uit de + extensie al duidelijk is, in welk schermtype het plaatje + staat, (zoals bij .SC8 of .S12) stelt het programma dit zelf + in en bewaart dit later ook in de PCD file, zodat u het + plaatje altijd in het juiste schermtype kunt bekijken. + + Indien het niet te achterhalen is, vraagt het programma u in + welk schermtype de plaat behoort te staan. Als het packen + gelukt is kan het programma vragen, of het plaatje "high" + geladen moet worden. Later meer hierover. Daarna vraagt het + programma of het oude plaatje verwijderd moet worden. Het is + met de nieuwe versie WEL mogelijk om plaatjes weer in hun + oorspronkelijk formaat terug te zetten! (Zie info over de + depacker.) + + + B E K I J K E N E N T E R U G Z E T T E N + + Om plaatjes te bekijken of weer terug te zetten in hun + normale vorm laadt men PICDPACKR.BAS. Na het starten geeft + het programma een overzicht van alle PCD's in de huidige + directory. U hoeft nu alleen de filenaam zonder de extensie + PCD in te typen. + + Als u een piep hoort, betekent dat, dat het plaatje "hoog" + in het schermgeheugen staat. Het plaatje wordt nu getoond. + Typt u S als hij klaar is, dan wordt het plaatje gesaved met + dezelfde filenaam, maar met de extensie .SC7 .SC8 of .S12 + voor respectievelijk SCREEN 7, 8 en 12 plaatjes. U kunt het + plaatje nu weer gewoon met BLOAD ,S inladen. Typt u P, dan + savet (wat een woord) het programma het plaatje met de + extensie .PIC zodat u het met Designer Plus [Nvdr. en andere + rotte programma's] gelijk kunt inladen en bewerken. + + Nog even wat "technische" informatie. Om plaatjes te packen + moeten ze in een vorm staan zoals ze met BSAVE ,S worden + bewaard. De indeling van de eerste bytes van een PCD zien er + als volgt uit: + + 00H altijd waarde 224 (=alpha) + 01H geeft aan of plaatje hoog of laag in het geheugen staat + 108 (="L") is laag en 104 (="H") is hoog. + 02H deze byte bevat het schermnummer waarin het plaatje + staat. + 03H + .. zijn ongebruikt. Hier kan nog aanvullende info komen. + .. + 09H + 0Ah het begin van het plaatje + + Opmerking: er staat nergens hoelang de PCD is. De depacker + kijkt gewoon, of het scherm (0000H-D3FFH) vol is. + + Als het plaatje hoog in het VRAM wordt geladen wordt bij + deze indeling gwoon D400H opgeteld. D401H bevat dan 104. Het + hoog laden heeft als nut, dat bij het depacken slechts 1 + page wordt gebruikt en ook nog iets sneller is. + + Het lijkt me niet alt te moeilijk, om van deze programma's + ook een machinetaal versie van te maken, zodat het nog veel + sneller werkt. Wie? + + + V O L G E N D E K E E R + + Op die vectorgraphics maker zult u nog even moeten wachten. + Ik heb na drie maanden wachten EINDELIJK het boek te pakken + gekregen dat mij misschien verteld hoe ik onzichtbare lijnen + ook onzichtbaar moet laten worden. (Wat een smoes...) + + Volgende keer een spraaksynthese programma dat, jawel, + NEDERLANDS praat! Wel met een Frans accent (ja accent + spreekt-ie ook goed uit) maar het was oorspronkelijk een + Frans programma. Alleen nog even maken dat hij ook woorden + als "mooie" goed uitspeekt... (mooieju) + + Groeten! + Randy Simons + \ No newline at end of file diff --git a/sunrise_special/5/R800 rom ram lezen.md b/sunrise_special/5/R800 rom ram lezen.md new file mode 100644 index 0000000..8b80d53 --- /dev/null +++ b/sunrise_special/5/R800 rom ram lezen.md @@ -0,0 +1,53 @@ + R 8 0 0 R O M / R A M L E Z E N + + + Met het volgende BASIC-programmaatje heb ik even het + snelheids-verschil tussen ROM- en RAM-gebruik van de R800 + gemeten. (Staat op disk onder de naam TESTER.BAS.) + + 100 TIME=0 + 110 _TURBO ON + 120 FOR I=0 TO 16384 + 130 IF I/100=I\100 THEN LOCATE 0,0: PRINT I/100 + 140 NEXT I + 150 PRINT TIME + + Regel 130 kan natuurlijk veel beter. I/100=I\100 kan + namelijk worden vervangen door I MOD 100=0. Het "\" teken + staat voor integerdeling. Met MOD is de rest te bepalen van + een integerdeling. Maar doordat ik "/" gebruik duurt het wat + langer, en zijn de resultaten nauwkeuriger. + + + T A B E L L E T J E + + | RAM | ROM + ------------+------+------- + Z80 | 2074 | 2075 + ------------+------+------- + R800-ROM | 255 | 1000 + ------------+------+------- + R800-DRAM | 246 | 981 + + + De getallen zijn de resultaten bij mijn turbo R op 60 Hz. + Bij RAM heb ik KUN-BASIC in RAM (de diskversie dus) gebruikt + en bij ROM KUN-BASIC in een ROMmetje. + + Het valt direct op dat er een groot verschil is tussen RAM + en ROM bij de R800-modes. In de R800-modes is hij gemiddeld + 3.95 keer langzamer, terwijl het in de Z80-mode geen ene + moer uitmaakt. + + De conclusie uit deze cijfertjes is niet moeilijk te + trekken: bij het lezen van ROM schakelt de engine terug naar + de Z80-mode! + + Als je dus toevallig KUN op EPROM hebt, kun je toch nog + beter KUN in het geheugen inladen, omdat dat het zaakje 4 + keer versnelt in de R800-mode. Het maakt overigens niks uit + of dat geheugen het DRAM geheugen is (met READKANA + erinladen) of de gewone memory mapper. Wel vrees ik dat ook + een externe langzamer wordt aangestuurd. + + Kasper Souren diff --git a/sunrise_special/5/Rekenen op Z80.md b/sunrise_special/5/Rekenen op Z80.md new file mode 100644 index 0000000..ed64322 --- /dev/null +++ b/sunrise_special/5/Rekenen op Z80.md @@ -0,0 +1,611 @@ + R E K E N E N O P Z 8 0 + + + Vaak kijk ik met afgunst naar de MC68000. Deze fraaie + processor kan hardwarematig vermenigvuldigen en delen. De + R800 kan alleen dat eerste, maar doet dat toch redelijk + snel. De Z80 kent geen van beide en is daarmee vreselijk + beperkt. Vermenigvuldigen is nl. een zeer elementaire + rekenkundige aktie en is bij het minste of het geringste + nodig. Voor de Z80 zijn er daarom speciale vermenig + vuldigingsroutines bedacht. Zo is er in de MSX bv. de Math + Pack die ook nog vele andere rekenkundige funkties kent. + + Voordelen van de Math Pack: + - Groot bereik in berekeningen + - Grote nauwkeurigheid mogelijk + + Nadelen: + - Zo traag als een jichtige slak + + Dat traagheid van de Math Pack maakt hem per definitie + ongeschikt voor bv. toepassing in demo's. Omdat ik toch wat + wiskundige geintjes in ML wilde maken was het dus + noodzakelijk om snel te kunnen vermenigvuldigen. Ik ben toen + aan het programmeren geslagen met als resultaat een stel + .... trage vermenigvuldigingsroutines. Een paar maanden + later keek ik weer eens naar deze routines en besloot om het + nog eens te proberen. De resultaten van dat werk zijn in dit + artikel te vinden. + + + D E T H E O R I E + + Er zijn twee manieren om twee getallen met elkaar te + vermenigvuldigen. De eerste is wat je vroeger in de eerste + klas lagere school deed; herhaald optellen. + + Vb. 10 * 4 = 40 + 10 + 10 + 10 + 10 = 40 + + Eenvoudiger kan niet. Een praktische routine zal met deze + methode erg klein worden, maar wordt erg traag als de + lusteller (4 in het voorbeeld) groot wordt. De + berekeningstijd is dus sterk afhankelijk van de invoer en + kan ook nog eens extreem oplopen. Het nut van deze + berekeningsmethode is dus zeer beperkt. + + Een betere methode is de volgende: + + Vb: 10 * 4 + + 10 = A = 00001010B 4 = B = 00000100B + + Bit A + 0 0 C = B*2^0 * 0 = 4*01*0 = 0 + 1 1 C = B*2^1 * 1 = 4*02*1 = 8 + 2 0 C = B*2^2 * 0 = 4*04*0 = 0 + 3 1 C = B*2^3 * 1 = 4*08*1 = 32 + 4 0 0 + 5 0 C = B*2^5 * 0 = 4*32*0 = 0 + 6 0 0 + 7 0 C = B*2^7 * 0 = 4*128*0= 0 + -- + + 40 + + Als je niet ziet hoe het werkt, probeer het dan eens met + andere getallen. Indien een bit in A hoog is wordt bij het + antwoord B*2^bitnummer_van_A opgeteld. De voordelen t.o.v. + de eerste methode liegen er niet om: + - Berekeningstijd is maar weinig afhankelijk van de invoer. + - Levert snelle korte code op. + + Het zal dan ook niemand verbazen dat dit een veel gebruikte + methode is. Een vermenigvuldiging in PASCAL of C zal meestal + zo uitgevoerd worden. + + + 8 B I T S V E R M E N I G V U L D I G I N G E N + + R O U T I N E 1 + + ; A = B.C + A=BMLC: LD A,0 ; 7 + BMLC.0: ADD A,C ; 4 + DJNZ BMLC.0 ; B<>0 THEN 13 ELSE 8 + RET ; 10 + + De getallen achter de instrukties stellen het resp. aantal + klokpulsen dat de instruktie duurt voor. Met deze gegevens + is nu een formule op te stellen over de duur van een + berekening. + + t = init + B * luslengte + exit + wait states + + MSX is helaas behept met een wait state. Dat houdt in dat de + Z80 na elke instruktie 1 klokpuls wacht voordat doorgegaan + wordt. deze vertraging is daarom ook in de berekening + opgenomen. + + t = 7 + 17B - 5 + 10 + 2 + 2B + = 19B + 14 + + t = Tijdsduur van routine in klokpulsen + 7 = LD A,0 + 17B = B * (ADD A,C + DJNZ label) + -5 = Laatste DJNZ correctie die 5 klokpulsen sneller is. + 10 = RET + 2 = LD A,0 en RET wait states + 2B = ADD A,C + DJNZ label wait states + + Het aantal microseconden dat de routine duurt kan eenvoudig + gevonden worden door t door 3.57 te delen. + + + R O U T I N E 2 + + ; A= A.C + A=AMLC: LD B,8 ; 7 + EX AF,AF ; 4 + LD A,0 ; 7 + EX AF,AF ; 4 + AMLC.0: RRCA ; 4 + JP NC,AMLC.1 ; 10 + EX AF,AF ; 4 + ADD A,C ; 4 + EX AF,AF ; 4 + AMLC.1: RLC C ; 8 + DJNZ AMLC.0 ; B<>0 THEN 13 ELSE 8 + EX AF,AF ; 4 + RET ; 10 + + twc = 'worst case' berekeningstijd (A = 11111111B) + = 22 + 8(14+12+21) - 5 + 14 + 62 + = 31 + 376 + 62 + = 469 + Twc = 469/3,57 = 131 us (microseconden) + + tbc = 'best case' berekeningstijd (A = 00000000B) + = 22 + 8(14+21) - 5 + 14 + 38 + = 31 + 280 + 38 + = 349 + Tbc = 349/3,57 = 98 us + + Omdat de berekeningstijd altijd afhankelijk is van de invoer + (maar in mindere mate dan bij routine 1) is er een worst en + best case berekening nodig. + + De routine begint met (22) en eindigd (14) met een aantal + instrukties. Daarnaast is er ook nog de loop die per + definitie 8 keer doorlopen wordt. Het aantal klokpulsen van + de lus moet dus met 8 vermenigvuldigd worden. De laatste + loop duurt echter 5 klokpulsen korter en deze worden weer + bij het resultaat afgetrokken. Natuurlijk moeten ook hier de + wait states weer bij de berekening betrokken worden. + + Het kan echter nog beter dan dit. + + R O U T I N E 3 + + ; A = A.C + A=AMLC: LD D,A ; 4 + LD A,0 ; 7 + LD B,8 ; 7 + AMLC.0 RRC D ; 8 + JP NC,AMLC.1 ; 10 + ADD A,C ; 4 + AMLC.1 RLC C ; 8 + DJNZ AMLC.0 ; B<>0 THEN 13 ELSE 8 + RET ; 10 + + twc = 18 + 8(18+4+8+13) - 5 + 10 + 44 + = 23 + 344 + 44 + = 411 + Twc = 411/3,57 = 115 us + + tbc = 18 + 8(18+8+13) - 5 + 10 + 36 + = 23 + 312 + 36 + = 371 + Tbc = 371/3,57 = 104 us + + Deze routine heeft slechtere best case prestaties dan + routine 2, maar de worst case prestaties zijn beter. Deze + twee getallen liggen ook dichter bij elkaar dan bij routine + 2 waardoor de berekeningstijd dus constanter is. Daarmee is + routine 3 beter dan routine 2. + + Routine 1 is sneller dan routine 3 indien: + + 14 + 19B = 411 + 19B = 397 + B = 20.9 ==> 21 + + Sneller indien B<21 (worst case) + + + 1 6 B I T S V E R M E N I G V U L D I G I N G E N + + Bij deze manier worden niet twee 16 bits getallen met elkaar + vermenigvuldigd, maar een 8 bits en een 16 bits getal. Een + echte 16 bit * 16 bit vermenigvuldiging levert een veel + tragere routine op en is daarmee vaak ongeschikt. + + + R O U T I N E 4 + + ; HL = B.DE + BMULDE: LD HL,0 ; 10 + B.DE.0 ADD HL,DE ; 11 + DJNZ B.DE.0 ; B<>0 THEN 13 ELSE 8 + RET ; 10 + + t = 10 + B(11 + 13) - 5 + 10 + 2 + 2B + = 26B + 17 + + + R O U T I N E 5 + + ; HL = A.HL + AMULHL: LD B,8 ; 7 + LD DE,0 ; 10 + A.HL.0: RRCA ; 4 + JP NC,A.HL.2 ; 10 + EX DE,HL ; 4 + ADD HL,DE ; 11 + EX DE,HL ; 4 + A.HL.1: ADD HL,HL ; 11 + DJNZ A.HL.0 ; B<>0 THEN 13 ELSE 8 + EX DE,HL ; 4 + RET ; 10 + + twc = 17 + 8(14 + 19 + 11 + 13) - 5 + 14 + 36 + = 542 + Twc = 542/3,57 = 152 us + + tbc = 17 + 8(14 + 11 + 13) - 5 + 14 + 36 + = 366 + Tbc = 366/3,57 = 103 us + + + R O U T I N E 6 + + ; HL = A.DE + AMULDE: LD B,8 ; 7 + LD HL,0 ; 10 + A.DE.0: RRCA ; 4 + JP NC,A.DE.1 ; 10 + ADD HL,DE ; 11 + A.DE.1 SLA E ; 8 + RL D ; 8 + DJNZ A.DE.0 ; B<>0 THEN 13 ELSE 8 + RET ; 10 + + twc = 27 + 8(14 + 11 + 29) - 5 + 51 + = 505 + Twc = 505/3,57 = 142 us + + tbc = 27 + 8(14 + 29) - 5 + 43 + = 409 + Tbc = 409/3,57 = 115 us + + + N E G A T I E V E G E T A L L E N + + De genoemde routines zijn ongeschikt voor negatieve + getallen. Indien de hoogste bits van beide invoergetallen + nl. als tekenbit gebruikt worden, zal overflow natuurlijk om + de haverklap optreden. Jammer genoeg is het voor bv. + vectorgraphics wel van essentieel belang dat met negatieve + getallen gerekend kan worden. Het is echter wel mogelijk om + de routines wat uit te breiden waardoor dit probleem + opgelost wordt. + + Het is niet helemaal waar dat de routines niet met negatieve + getallen om kunnen gaan. In het geval van routine 6 mag A + bij invoer niet negatief zijn, maar DE wel. Dit komt omdat + DE per lus alleen maar met 2 vermenigvuldigd wordt, waarbij + eventuele overflow geen invloed heeft. Dat levert voor + routine 6 de volgende routine op. + + ; In : A , Integer parameter 1 + ; DE, Real parameter 2 + ; Out: HL, Real antwoord + SAMLDE: BIT 7,A + JP Z,AMULDE ; (Met LD B,7) + NEG ; Maak A positief + CALL AMULDE ; (Met LD B,7) + LD DE,0 + EX DE,HL + OR A + SBC HL,DE ; Inverteer antwoord + RET ; omdat A ook ge�nverteerd is. + + Deze methode heeft drie consequenties: + - De routine wordt wel iets trager (meer 'overhead') + - Het bereik wordt verschoven naar -32768 tot 32768 + - De loopcounter in AMULDE kan nu van 8 naar 7 gezet worden + omdat bit 7 van A altijd 0 zal zijn. Hierdoor wordt de + extra overhead weer teniet gedaan. + + Met deze routine erbij is het gebruik van negatieve getallen + geen probleem meer, terwijl het geheel amper trager zal + worden. + + + Het volgende deel van dit artikel staat in het submenu. + + + + Het eerste deel vindt u in het submenu. + + + P R A K T I S C H G E B R U I K + + Het grote nadeel van alle genoemde routines is dat het + bereik t.o.v. de Math Pack relatief klein is. Daar komt nog + bij dat het moeilijk is om op overflow fouten te testen. + Dergelijke tests zijn niet ingebouwd omdat dat de routines + aanzienlijk trager maakt. Je kunt je dus afvragen wat het + pratische nut van de routines is. Welnu, dat hangt + natuurlijk helemaal van de applicatie af. Zo kan bv. + worteltrekken beter via de Math Pack gedaan worden. Is het + de bedoeling dat een kogeltje in een schietspel in een + rechte lijn van punt A naar punt B gaat, dan zijn juist deze + routines weer uitermate geschikt. + + Een groot nadeel is dus het feit dat je door het kleine + bereik enorm op overflow situaties op moet passen. Zou je in + routine 6 de getallen 200 en 400 met elkaar + vermenigvuldigen, dan is dat al meer dan 65535 (het + theoretische maximum). + + Overflow is echter te voorkomen door alleen maar 8 bits + getallen met elkaar te vermenigvuldigen. Het produkt van 2 + 8-bits getallen kan nl. maximaal 16 bits groot zijn. De + genoemde 8x16 bits routines kunnen dus het beste als 8x8 + bits routines gebruikt worden. Overflow is dan onmogelijk. + De 8x8 bits routines hebben met hun 8 bits antwoord nog wel + last van overflow. + + Het gebruik van deze routines moet in de grafische omgeving + gezocht worden. Neem bv. SCREEN 5, waar de maximale + resolutie 256x256 pixels is. Omdat de resolutie binnen 8 + bits past is het dus mogelijk om de vermenigvuldigingen voor + bv. pixeleffekten en zelfs vectorgraphics te gebruiken (elk + pixel valt binnen het bereik van de routines). + + + A L T E R N A T I E V E G E T A L N O T A T I E + + Het vermenigvuldigen van twee integers (een heel getal + tussen 0 en 255) is geen enkel probleem met deze routines, + maar daar bereik je niet veel mee. Om een goed praktisch + gebruik mogelijk te maken is een andere zienswijze op + hexadecimale getallen nodig. + + 1000H = 16*256 = 4096 + Dit klopt als een bus, maar wat gebeurt er als we een komma + midden in het hexadecimale getal zetten ? + + 10,00H = 16,00 = 16 + Ook dit is geen probleem. We beschouwen het HI-byte van het + getal als integer en het LO-byte als fraktie. Hiermee is de + mooie 16 bits integer verandert in een 16 bits real. + + Als we de zaken nu eens omdraaien. Hoe representeer je het + getal 13,5 (decimaal) in hexadecimale vorm ? + + 13,5 = 0D80H + 13 = 0DH, dit lijkt me geen probleem. + 0,5 = 80H, dit is wat lastiger. + + Een integer in hexadecimale notatie heeft dezelfde waarde + als dezelfde integer in decimale, binaire of elk ander + willekeurig talstelsel. Hoe anders is dit bij een breuk, + waar het getal achter de komma afhankelijk van het + talstelsel is. + + Als we twee getallen achter de komma afspreken (dat past nl. + mooi in ��n byte), dan kan een decimaal getal dus 100 + mogelijke frakties hebben (0,00 t/m 0,99) en een + hexadecimaal getal 256 (0,00 t/m 0,FF). De omrekening van + een decimale naar een hexadecimale fraktie gebeurt door de + decimale fraktie met 2,56 te vermenigvuldigen. + + Vb: 0,5 ==> 50 ==> 50*2,56 = 128 ==> 0080H + 0,5 ==> 0,5*256 = 128 ==> 0080H + + 20,23 decimaal is dan 143BH (afgerond) + 10,25 decimaal is dan 0A40H + (Ter vergelijking: 1025 decimaal = 0401H) + + Het leuke is dat een hexadecimale fraktie 2,56 keer zo + nauwkeurig is als een decimale (256 mogelijkheden i.p.v. + 100). + + De mogelijkheden die het gebruik van een fraktie met zich + mee brengt zijn buitengewoon aardig. Om te beginnen kunnnen + we nu een integer tussen 0 en 255 vermenigvuldigen met een + waarde die ligt tussen 0,0 en 0,FFH in stappen van 0,01H. + Indien ook negatieve getallen mogelijk zijn loopt het bereik + van -80,00H t/m 7F,FFH. Een praktische aanroep ziet er als + volgt uit. + + LD A,200 + LD DE,&H0040 + CALL AMULDE + (HL is nu 3200H, H = 32H = 50) + + Deze routine voert de berekening 200*0,25 = 50 uit. Let op + dat overflow niet voorkomt omdat twee 8 bits getallen + vermenigvuldigd worden tot een 16 bits antwoord. Bij het + antwoord is H het getal voor de komma en L de fraktie achter + de komma. + + + N E G A T I E V E F R A K T I E S + + Ook met deze getalrepresentatie zijn negatieve getallen + mogelijk. Het inverteren van een reeds naar een fraktiegetal + omgezette decimaal gaat gelukkig op precies dezelfde manier + als het omzetten van een pure integer. + + Vb: 100 = 64H + -100 = 256 - 100 = 9CH + + 10,23 ==> 0A3BH + -10,23 ==> 10000H - 0A3BH = F5C5H + + Je moet hier dus wel oppassen dat ook de fraktie van een + negatief getal anders is dan die van hetzelfde positieve + getal. Het veranderen van de fraktie moet echter gebeuren + omdat de berekeningen anders in de soep lopen. Bovendien + kunnen positieve en negatieve getallen ook willeurig + opgeteld en afgetrokken worden. + + Vb: + 30,23 ==> 1E3BH + -20,75 ==> EB40H + ------ + ----- + + 9,48 097BH + + 7BH = 123 ==> 123/2,56 = 48 + + De extra code die nodig is om met bv. routine 6 negatieve + getalberekeningen mogelijk te maken werkt ook met deze + getalnotatie (het zou niet best zijn als dat niet zo zou + zijn). + + + L I J N T J E R E K E N E N + + Omdat we aannemen dat DE een breuk is, is het nu bv. + mogelijk om een lijn te 'berekenen', wat overeen komt met + een punt dat door berekening in een rechte lijn van punt A + naar punt B gaat. Dat gaat als volgt. Een lijn kan gezien + worden als de schuine zijde van een rechthoekige driehoek. + Daarmee heeft een lijn dus een delta X en een delta Y. We + nemen deze even gelijk en stellen dat we een lijn willen + tekenen van coordinaat (0,0) tot (49,49). + + LD B,0 ; Lusteller + LUS: PUSH BC + LD D,0 ; DE loopt van 0,0 tot 0,FFH + LD E,B + LD A,50 ; = delta X = delta Y + CALL AMULDE + LD A,H + CALL PSET ; Teken pixel op coord. (A,A) + POP BC + DJNZ LUS + + Dit theoretische programmaatje zal 256 punten berekenen + tussen de coordinaten (0,0) en (49,49). Wat er feitelijk + gebeurt is dat delta X en delta Y per lus met een oplopend + getal vermenigvuldigd worden dat tussen DE=0 en DE=00FFH + ligt. Na de vermenigvuldiging staat de rest in register L, + maar die waarde is hier niet van belang (je kunt immers + tussen twee pixels niet nog een pixel tekenen). Let op dat + wanneer een lijn getekend wordt van (0,0) - (5,5), er ook + 256 punten berekent worden. Er worden dus 256/5 pixels op + dezelfde positie berekend! Om dat probleem op te kunnen + lossen moet je maar eens aan Piet Apegras denken (lengte van + schuine zijde). + + + I N T E G E R S D E L E N + + Delen is niets anders dan vermenigvuldigen met het + omgekeerde. Dat klinkt heel simpel, maar dat valt praktisch + wat tegen. Dit is overigens zeer recente informatie. Ik heb + de delingsmethode die ik hier ga noemen pas bedacht toen ik + met dit artikel bezig was (er ging mij een lichtje op). + + Vb: + + 50 / 13 = 3,8462 + Maar ook: 50 * 1/13 = 3,8462 + + De deling kan uitgevoerd worden door de vermenigvuldigen met + 1/13 i.p.v. delen door 13. Aangenomen dat we alleen maar + integers door integers willen delen (met een real als + antwoord) kan een tabel gemaakt worden met de waarden 1/2 + t/m 1/255. Gebruik makend van de bij onze vermenig + vuldigingen toegepaste fraktie zal die tabel er als volgt + uit zien. + + 1/002 = 0,50 + 1/003 = 0,67 + 1/004 = 0,25 + 1/010 = 0,10 + 1/100 = 0,01 + 1/110 = 0,00... + 1/128 = 0,00... + 1/200 = 0,00... + 1/255 = 0,00... + + Bij de wat grotere delers blijkt dat twee getallen achter de + komma niet voldoende is. Vanaf 1/101 zal het antwoord altijd + 0 zijn. Je begrijpt, een deling zal op deze manier bijna + nooit kloppen. Met twee extra decimalen gaat het al stukken + beter. 1/253 wordt dan 0,0040 en 1/255 wordt 0,0039. Een + omzetting naar een hexadecimale fraktie levert nu echter ook + een 16 bits getal op dat echter wel 2,56 keer zo precies is. + + De berekening in ons voorbeeld moet nu als volgt uitgevoerd + worden: + + 50/13 = 32H/13 + + 1/13 ==> (1/13)*256*256=5041 == 13B1H Er moet 2 keer met 256 + vermenigvuldigd worden omdat we een 4 decimalen nauwkeurige + fraktie willen hebben. Het antwoord is nu een 16 bits + fraktie. + + Berekening gaat nu als volgt: + + 32H * B1H = 2292H + 32H * 13H = 03B6H + ------- + + 03D8H + + Terugrekening naar decimalen: + D8H = 216 ==> 216/256 = 0,8438 + 03H = 3 ==> 3 + ------ + + 3,8438 + Met de rekendoos: 50/13 = 3,8462 + ------ - + Absolute fout: -0,0024 + + Het verschil wordt veroorzaakt door de 92H van de eerste + berekening die verwaarloosd wordt en afrondingsfouten bij + het omzetten van decimaal naar hexadecimaal. Deze methode is + twee getallen achter de komma nauwkeurig en dat is precies + genoeg. + + Om te kunnen delen moet dus eerst een tabel gemaakt worden + met 16 bits frakties van de delingen 1/2 t/m 1/255 (delen + door 0 mag niet, en delen door 1 levert geen fraktie op). + Daarnaast moeten om ��n deling te doen twee + vermenigvuldigingen en een optelling gedaan worden. + + Indien de nauwkeurigheid van het antwoord niet van uiterst + belang is, kan de eerste vermenigvuldiging ook overgeslagen + worden (dus alleen 32H * 13H). De absolute fout is dan 1. + Vb: + 8000H + 02F0H + ------- + + 0370H + + Indien de eerste vermenigvuldiging overgeslagen wordt zou + het antwoord 02F0H zijn, zodat de absolute decimale fout 0,5 + zou worden. Het hangt van de applicatie af of dit gedaan kan + worden, maar het levert natuurlijk wel een behoorlijke + snelheidswinst op. + + Helaas is deze methode alleen maar geschikt om twee integers + te delen. Dat is dan ook meteen het nadeel van deze methode, + want het maakt nogal wat uit of je 200 door 1 of 1,9 deelt. + Hoe dit het uiteindelijke plaatje bij bv. vectorgraphics + be�nvloedt is mij (nog) niet bekend, maar ik kan me + situaties voorstellen waarbij de deling van alleen integers + te weinig nauwkeurigheid biedt. Helaas zal een routine die + twee 'real' 16 bits getallen deelt ontzettend traag worden. + + + C O N C L U S I E + + Gewapend met de vermenigvuldigingen en de deling is het nu + mogelijk om 'real-time' vector graphics te maken zonder + tussenkomst van de Math Pack. De echte vector freaks kunnen + hun hart dus weer eens ophalen. Ook het maken van een + fractal berekeningsprogramma is met deze routines mogelijk, + maar dat is al door XelaSoft gedaan. + + Als je deze berekeningsroutines eens aan het werk wilt zien, + dan moet je maar eens de Fuzzy Logic demo's 'Math Magicians' + of 'MB Musax 1' bekijken. De bestuurbare sterrenhemel in + deze produkten werkt op hetzelfde principe als de lijn + berekening. De delta X en Y zijn hier per lus echter + variabel waardoor de sterren kunnen draaien. Dit geintje + wordt dus NIET bereikt door een enorme tabel in het geheugen + op te slaan waar alle mogelijke posities in staan. Ook de + snelheid van de routines blijkt uit deze routines. In 1/60 + seconde worden nl. 64 vermenigvuldigingen uitgevoerd om 32 + sterren te besturen. + + + Alex van der Wal + F U Z Z Y L O G I C diff --git a/sunrise_special/5/Shem.md b/sunrise_special/5/Shem.md new file mode 100644 index 0000000..c6c01c9 --- /dev/null +++ b/sunrise_special/5/Shem.md @@ -0,0 +1,53 @@ + S H E M + + + SHEM is een Japans monitorprogramma. Het is een vrij + uitgebreid programma, en het is de moeite waard het eens te + bekijken. Met [TAB] kun krijg je een overzicht van de te + gebruiken commando's. Ik zal in het kort even een paar + dingen uitleggen. + + + D I S A S S E M B L E R + + De pijl die onderaan staat betekent dat die commando's + alleen te gebruiken zijn in de disassembler. Met CTRL-A kun + je bijv. assembleren. + + De R800-instructies MULUB en MULUW worden trouwens goed op + het scherm gezet. + + + S O M - M O D E + + CTRL-C verandert de "som-mode". Aan de rechterkant van het + scherm is hiervoor plaats gereserveerd. Je kunt switchen + tussen de volgende modes: MSX, STD8, STD16 en SUM16. Het nut + hiervan is me niet compleet duidelijk, maar in ieder geval + worden de waarden die op de regel ernaast staan allemaal bij + elkaar opgeteld. + + + P A G E 0 V E R A N D E R E N + + Als je de slot- of mapper-stand page 0 verandert, blijft het + programma hangen. Dit is dus niet aan te raden. + + Met CTRL-W is de mode van de graphic window in te stellen. + Dit is een zeer leuke optie, omdat je zo een beter overzicht + hebt. En misschien is het zijn graphics ook nog een beetje + zichtbaar. + + Met [INS] of [CTRL][DOWN] kun je snel omlaag scrollen, en + met [DEL] of [CTRL][UP] snel omhoog. + + + M O N I T O R O F D E B U G G E R ? + + Als je SHEM vergelijkt met MSX-Debug van MSX-Club Enschede, + komt SHEM er wel matig vanaf, als je hem tenminste als + debugger gebruikt. Als je SHEM echter als volwaardige + monitor beschouwt, met als extra een disassembler, is het + toch wel een zeer goed programma! + + Kasper Souren diff --git a/sunrise_special/5/Software projecten deel 1.md b/sunrise_special/5/Software projecten deel 1.md new file mode 100644 index 0000000..f90ea00 --- /dev/null +++ b/sunrise_special/5/Software projecten deel 1.md @@ -0,0 +1,450 @@ + S O F T W A R E P R O J E K T E N D E E L 1 + + + Welkom bij deel 1 van de 'cursus' software projekten. Zoals + beloofd in de inleidende tekst gaan we vanaf nu wat dieper + in op de vraag wat men in elk systeem tegen komt en wat daar + aan te programmeren valt. In dit deel zal ik de problemen en + mogelijkheden van een standaard filesysteem behandelen. Een + filesysteem is een verzameling routines waarmee data van elk + denkbaar type geladen en verwerkt kan worden. Het moge + duidelijk zijn dat dit een zeer belangrijk onderdeel van elk + softwareprojekt is. Zo belangrijk zelfs, dat de kwaliteit + van de rest van het systeem sterk afhankelijk is van de + mogelijkheden van het filesysteem. + + Ik zal waarschijnlijk wel weer wat woorden door elkaar heen + gebruiken. Woorden als softwareprojekt en systeem, + softwarelagen en niveaus zijn synoniemen van elkaar. + + Een wat groter softwareprojekt heeft: + - invoer + - uitvoer + - programma code + - data + + + I N V O E R + + Dit kan natuurlijk van alles zijn. Bij een tekstverwerker is + het invoer van een toetsenbord, muis of joystick, maar ook + van een achtergrondgeheugen (diskette of harddisk etc.). Dit + zelfde geldt voor een tekenprogramma. Je kunt wel stellen + dat ELK groter programma achtergrondgeheugen gebruikt. + Daarom zal een eigen systeem een goed uitgedokterd + filesysteem nodig hebben. + + + U I T V O E R + + ELK programma [Nvdr. TSR's soms niet!] zal uitvoer naar het + scherm hebben. Zelfs het meest pietepeuterige programmaatje + heeft het al, dus dit is iets om rekening mee te houden. Als + het al mogelijk is om iets van achtergrond geheugen te + lezen, dan zal het schrijven daar naartoe ook wel handig + zijn. Bij een tekstverwerker of tekenprogramma is dit + natuurlijk vanzelfsprekend, maar het gemiddelde spel zal + daarentegen maar weinig naar achtergrond-geheugen schrijven. + + + P R O G R A M M A C O D E E N D A T A + + Ook dit is iets wat elk programma zal hebben. De problemen + die deze datavormen opleveren zijn per projektsoort anders. + Bij een tekstverwerker zal over het algemeen maar weinig + extra code bijgeladen hoeven te worden tijdens normaal + bedrijf, maar bij spellen is dat andere koek. + + + F I L E H A N D L I N G + + Uit deze beschrijvingen blijkt dat er altijd behoefte + bestaat om data van en/of naar een achtergrondgeheugen te + transporteren d.m.v. een filesysteem. Een standaard + filesysteem is daarom ook enorm handig is om altijd bij de + hand te hebben. Hoe vaak is het ons ook al niet overkomen + dat we voor elke demo nieuwe laadroutines hebben geschreven + omdat de oude plotseling niet meer handig bleken. Het + schrijven van dit soort code is 'dom' werk dat feitelijk zo + standaard hoort te zijn dat het maar ��n keer gedaan hoeft + te worden. Een filesysteem is zo'n cruciaal onderdeel van + elk softwareprojekt dat het daarom niet verkeerd is om dit + als eerste te schrijven van waaruit de rest van het systeem + kan groeien. Een filesysteem is als het ware de ruggegraat + van de rest van de software. + + Verder zijn laad- en saveroutines natuurlijk per direkt te + gebruiken om andere delen van je eigen systeem mee te maken. + Dus tijdens de ontwikkelfase kan je meteen al van deze + routines gebruik maken wat natuurlijk ontzettend handig is. + + + Wat zal het gemiddelde filesysteem moeten kunnen? + 1) Laden van data + 2) Schrijven van data + + Dat lijkt simpel genoeg, ware het niet dat de data zo + verschillend van aard kan zijn. Mogelijke datasoorten zijn + bijv.: + - Algemene data + - Code + - Graphics + - Paletten + - Sprite data + - Muziek + - Samples + + Samples en muziek zullen voor de gemiddelde tekstverwerker + van ondergeschikt belang zijn, maar ik vind het toch een + goed idee om een gezonde 'link' naar een eigen spel te + leggen. + + Algemene data en code zijn eigenlijk ��n en dezelfde tenzij + codefiles van het BLOAD type zouden zijn en de datafiles + niet. Het is verstandig om beide typen gelijk te kiezen, wat + nl. in code scheelt. + + Graphics hebben twee eigenschappen waardoor ze zich van + normale data onderscheiden: + - Ze kunnen gecruncht zijn + - Ze moeten uiteindelijk in VRAM terecht komen. + + Of je wel of niet gecrunchte graphics gebruikt, je zal RAM + nodig hebben om de grafische data tijdelijk in op te slaan + voordat het naar VRAM gekopieerd wordt. Praktisch kost dit + minimaal 16 kB, die voor de rest van de tijd voor andere + doeleinden te gebruiken is. Overigens is het ook heel goed + mogelijk dat er meerdere grafische formaten zijn. Dit kan je + het beste vergelijken met het COPY "filenaam.ext" en BLOAD,S + commando in BASIC. Beide zijn grafische laadroutines, die + echter verschillende dataformaten gebruiken. + + De andere filetypes: paletten, sprite data, muziek en + samples; het enige wat ze gemeen hebben is dat ze allemaal + een eigen specifieke behandeling nodig hebben. + + + B E S T E M E T H O D E V O O R D A T A + + Er blijken net zoveel datatypen als algoritmen om deze data + te verwerken te zijn. Of je nu dus wel of niet een standaard + filesysteem maakt, er zullen hoe dan ook routines geschreven + moeten worden om de verschillende datatypen af te handelen. + Met dat gegeven kunnen we meteen een stap verder gaan, want + wat zal er nu theoretisch moeten gebeuren als een file + geladen wordt? + + 1) Geef opdracht om de file te laden + 2) Ga naar de betreffende afhandelingsroutine + 3) Laad de file + 4) Handel laadfouten af + 5) Verwerk de geladen data + + Stel je voor dat je bij elk te laden file zelf al deze + akties uit zou moeten voeren, daar wordt je toch helemaal + krankjorem van. Nee, dan de goede oude BASIC tijd waarbij + het laden van een grafische file en het afhandelen van het + daarbij horende palet een fluitje van een cent was m.b.v. + twee eenvoudige commando's. + + Het zou buitengewoon wenselijk zijn om elke mogelijke file + van elk mogelijk type even simpel te kunnen laden als in + BASIC het geval is. In assembly krijg je dan zoiets als: + + LD DE,FILADR ; Adres van filenaam string + ; Geef met andere registers de laadpositie aan + CALL GETFLE ; HAAL file!! + JP C,oeps ; Uh oh, een laadfout. + : + : + + FILADR: DM "FILENAME","EXT" + + END + + + De routine GETFLE moet nu het genoemde rijtje van 5 taken + uit gaan voeren. Het soort file is bv. via de extensie door + te geven (.PIC voor graphics, .COD voor code, .MBM voor de + muziek etc.). Dit systeem is al zo oud als DOS zelf en + waarom zouden we hier recalcitrant gaan doen? Bovendien is + het ook een prima manier om de dingen voor jezelf te + administreren. + + De laad-algoritmen hangen natuurlijk sterk af van de manier + waarop je de data opgebouwd hebt. Laat ik een grafisch + voorbeeld geven. Bij ons [Nvdr. Fuzzy Logic] is grafische + data ALTIJD gecruncht en bestaat uit blokken van 16 kB die + per blok gedecruncht kunnen worden. Het laadalgoritme is dan + bv. als volgt: + + - Zet het VRAM decrunchadres + - Laad een blok in het RAM + - Decrunch dat blok vanuit de tijdelijke RAM opslag. + - Herhaal dit tot de file volledig in het VRAM + gedecruncht is. + + Hier komt nu het grote voordeel van een routine als GETFLE + naar voren. Zodra deze standaard routine eenmaal geschreven + is, kan het je niet meer schelen HOE een file geladen wordt, + maar alleen nog maar DAT dit gebeurt. Laden, decrunchen en + foutafhandeling; dit alles gebeurt automatisch zonder dat je + er verder nog last van hebt. Men noemt zoiets een + 'hi�rarchisch niveau' of 'software laag'. Het komt er op + neer dat het routines binnen verschillende softwarelagen + niets kan schelen HOE de ander nu precies zijn werk doet, + maar er gewoon vanuit kan gaan dat het gebeurt. In het geval + van graphics moet de gebruiker van de routine GETFLE: + natuurlijk wel weten dat een bepaald blok RAM van 16 kB + gebruikt wordt, maar dat is nog altijd een stuk eenvoudiger + dan dat je alles tot in detail moet weten en regelen. + + + Deel 2 van deze tekst kunt u in het submenu vinden. + + + + - PART B - + + S O F T W A R E P R O J E K T E N D E E L 1 + + + H I E R A R C H I S C H E N I V E A U S + + Hi�rarchische niveaus heb je in vele soorten en maten. In + principe is je computer zelf al een verzameling niveaus, + maar het hangt van je uiteindelijke doel af hoeveel daarvan + van belang zijn. Een mogelijk overzicht van deze niveaus is + bijv. als volgt: + + Niveau 0, Elektronen binnen componenten + Niveau 1, Transistoren, weerstanden etc. + Niveau 2, Logische bouwstenen (AND en OR funkties etc.) + Niveau 3, Complexe bouwstenen (zoals de CPU) + Niveau 4, CPU Microcode + Niveau 5, Machinetaalprogramma's + (Niveau 6, Hogere talen) + Niveau 7, Operating System + Niveau 8, Applicaties + + Overigens bestaat er niet een gedefinieerde toewijzing van + niveaus, en de toewijzing ervan is dan ook een twistpunt + tussen computerguru's. Een leuk aspekt is echter dat de + scheiding waar de hardware eindigt en de software begint per + type computer verschillend is. De ene computer bijv. kan wel + hardwarematig vermenigvuldigen en de andere niet. + + Je begrijpt dat de manier waarop de elektronen over de print + van je computer lopen voor de gemiddelde software applicatie + niet echt interessant is. Dit voorbeeld laat alleen maar + even zien hoe de verschillende niveaus opgebouwd KUNNEN + zijn. GETFLE zou in dit voorbeeld een niveau zijn binnen het + Operating System niveau, maar zelfs daar kan je over + twisten. + + Het hebben van dergelijke niveaus is echter cruciaal voor + het welslagen van een groot software projekt. Het stelt je + nl. in staat om de complexiteit van het probleem als geheel + te verdelen over meerdere (in principe ook wel los werkende) + modules. Indien je dit niet doet, zie je na een paar weken + programmeren de bomen door het bos niet meer en is je code + gegarandeerd een puinhoop geworden. Is dat het geval, stop + dan twee maanden (om je hoofd even leeg te maken) en begin + opnieuw; deze keer met een goede opzet. Overigens is het + onderscheiden van niveaus binnen je software niet expliciet + hetzelfde als modulair programmeren (waar ik het in het + verleden al eens over gehad heb en waarbij de Italiaanse + kookkunst uitgebreid aan de orde is geweest), maar de twee + gaan wel hand in hand samen. + + + A F H A N D E L I N G V A N F I L E T Y P E S + + Ik kan voor bepaalde standaard filetypes wel gaan behandelen + hoe je deze verwerkt, maar de meeste verwerkingsroutines + zijn gewoon sterk afhankelijk van hoe deze files zijn + opgebouwd. Deze routines zal je dus zelf moeten schrijven, + waarbij je van tevoren goed moet nadenken hoe je het jezelf + zo gemakkelijk mogelijk kunt maken. + + Neem nu een MoonBlaster muziekfile. Een datafile van dit + type mag in principe overal in het geheugen komen te staan. + Indien je dus geen vaste plaats voor .MBM files aanwijst zal + je dus elke keer aan de MoonBlaster afspeelroutine moeten + vertellen waar deze de data kan vinden. Het is een + peuleschil om dit binnen GETFLE te doen, het moet per + definitie gebeuren, dus waarom zou je dit dan niet standaard + doen binnen de afhandelingsroutine? Nadat nu een .MBM file + geladen is met GETFLE hoeft de muziek alleen nog maar + aangezet te worden en klaar is Kees. Het is hierbij wel + belangrijk dat de afspeelroutine standaard onderdeel van je + verzameling routines is, en dat geldt bv. ook voor een + mogelijke grafische data decruncher. Het voorbeeld met de + MoonBlaster file laat duidelijk zien dat je de verwerking + van zo'n file niet meer exact hoeft te kennen, omdat het + automatisch gaat. + + Hetzelfde geldt voor samples die naar de Music Module + gekopieerd moeten worden. Waarom zou je het zelf doen als + het ook automatisch kan? Laad via GETFLE gewoon een .MBK + file en laat GETFLE maar uitzoeken of er een MSX-AUDIO met + sample-geheugen aanwezig is en indien ja, de sampledata naar + deze herrieschopper kopi�ren. + + Als je de zaken een beetje slim aanpakt is het mogelijk om + dingen waar je in het verleden dagen mee hebt lopen stoeien + ('ik kan die samples niet laden omdat ik geen 16 kB vrij + geheugen heb' of 'waar staat die decruncher ook alweer?') nu + met ��n CALL instruktie vlekkeloos uit te voeren. Als dat + geen vooruitgang is weet ik het ook niet meer. + + + F I L E S Y S T E E M N I V E A U S + + Een routine als GETFLE: staat natuurlijk op een vrij hoog + niveau binnen je filesysteem. Daaronder zullen zich toch nog + minimaal twee niveaus moeten bevinden om je filesysteem te + completeren. + + Filesysteem niveaus: + + Niveau 0: Interface naar de BDOS en foutafhandeling. + Niveau 1: Laad- en verwerkingsroutines voor de verschillende + filetypes. + Niveau 2: GETFLE-achtige routine(s) + Niveau 3: Mogelijke batchverwerker + + + N I V E A U 0 + + In een eerder artikel op Sunrise Special #4 heb ik al eens + lopen zeuren over de moeizame interfacing met de BDOS. + Ikzelf heb de routines die in de bijbehorende listing van + dat artikel horen bijna letterlijk gebruikt als niveau 0 + voor mijn eigen filesysteem. In het algemeen kun je stellen + dat in niveau 0 routines moeten komen die delen van, of + complete files kunnen laden. Hierbij is de foutafhandeling + natuurlijk van groot belang. + + Wat je ook schrijft voor niveau 0, de routines zullen toch + ongeveer hetzelfde doel moeten hebben als de bij SRS#4 + gegeven routines (anders in het geen niveau 0 meer). + + + N I V E A U 1 + + Hier komen de routines die files van een bepaald formaat + laden en verwerken. In een stuk hierboven is al het ��n en + ander vermeld over de routines die hier terecht moeten + komen. + + + N I V E A U 2 + + In niveau 2 staat op dit moment maar ��n routine; te weten + GETFLE (of soortgelijke). Het is echter helemaal niet + ondenkbaar dat hier meer routines komen. In mijn eigen + systeem heb ik nog een eigen RAMdisk zitten en een aantal + van de routines om de RAMdisk te besturen zijn in niveau 2 + te vinden (de meeste echter in niveau 1). + + + N I V E A U 3 + + Een batchverwerker? Wat is dat? Welnu, dit is een + verzameling routines waarmee het mogelijk is om niet ��n + file (zoals bij GETFLE) maar meerdere files achter elkaar te + laden en te verwerken (denk aan .BAT files in DOS). Dit kan + vooral bij spellen wel eens enorm makkelijk blijken, waar + van tijd tot tijd meerdere files geladen moeten worden + voordat verder gespeeld kan worden. De 'Batch' is een + tekstbestand dat in de teksteditor van je keuze gemaakt kan + worden. In deze tekst staan dan commando's die de + batchverwerker interpreteert en uitvoert. Afijn, of en hoe + je zoiets wilt implementeren moet je zelf maar weten. Bij + mijn systeem is de batchverwerker wat uit de kluiten + gegroeid en bevat naast file laadcommando's nu ook een + aantal commando's om data op een hoger niveau te verwerken. + + + N I V E A U G E G E V E N S U I T W I S S E L I N G + + Het aantal gegevens dat tussen de verschillende niveaus + uitgewisseld wordt moet zo klein mogelijk gehouden worden, + maar we kunnen ook niet zonder. Hoe zou je anders in GETFLE + een foutmelding terug kunnen krijgen als deze helemaal niet + weet wat er in de onderliggende niveaus in gebeurt? Wat voor + parameters er ook aan een niveau doorgegeven of ontvangen + worden, ze zullen in elk geval door moeten geven of iets + goed of fout gegaan is. Dat kan het beste met de Cy (=Carry) + gebeuren. Om nu conversieproblemen tussen de verschillende + niveaus tegen te gaan is het van belang dat alle niveaus hun + foutmeldingen via de Cy doorgeven. + + Een Cy gegenereerd bij een fysieke laadfout in niveau 0 moet + dus bij alle andere niveaus ook bekend gemaakt worden. + Niveau 2 weet dan bijv. wel DAT er iets fout is gegaan maar + nog niet precies WAT. Dat is echter ook niet belangrijk + omdat het in niveau 2 helemaal niet interessant is wat er is + fout gegaan. Het enige dat telt voor de routine op niveau 2 + (GETFLE) is dat deze nu weet dat het niet 100% zeker is dat + de data die geladen had moeten worden ook daadwerkelijk op + de plaats van bestemming is aangekomen. Met dit gegeven zal + een beslissing genomen moeten worden of het nog eens + geprobeerd wordt, of dat het programma moet stoppen. + + Alleen binnen niveau 0 is bekend wat de bron van de + foutmelding moet zijn geweest. Hier zit immers de + foutafhandling en het kan best zijn dat alleen maar de disk + offline is wat binnen niveau 0 prima op te lossen is door de + gebruiker te vragen deze als de bliksem weer terug te + stoppen. Een foutmelding naar hogere niveaus hoeft dan + natuurlijk niet meer gegeven te worden. + + Of het nu om een filesysteem of andere vorm van hi�rarchisch + systeem gaat, het teruggeven van foutmeldingen betekent + altijd hetzelfde. Een routine die een foutmelding + terugkrijgt weet dat de gewenste verandering aan het systeem + (geheugen, disk, registers binnen een chip of elk ander + onderdeel van de computer) niet gelukt is. We praten hier + over 'inconsistentie' van het systeem; het niet langer weten + HOE elk systeemonderdeel ingesteld is. + + Wat er precies moet gebeuren als dit gebeurt is afhankelijk + van de programmeur en de situatie. Bij een echte fysieke + laadfout kan maar het beste met het programma gestopt worden + waarna een boodschap op het scherm moet komen dat je diskje + kapot is. Daarentegen zal een fout m.b.t. het niet kunnen + vinden van een muis in de meeste gevallen wel anders op te + lossen zijn. + + + T O T S L O T + + Simpel is dit alles zeker niet. Een goede voorbereiding is + essentieel voor het welslagen van elk programma. Ga nu niet + als een bezetene ondoordachte code schrijven, maar werk + eerst op papier uit wat er in de verschillende niveaus moet + komen en hoe dat er per niveau ongeveer uit zal komen te + zien. Vooral de manier van gegevens doorgeven (en welke + gegevens) tussen de verschillende niveaus is verschrikkelijk + belangrijk. + + In dit eerste deel zijn de basisonderdelen van een + filesysteem besproken alsmede de manier waarop je zoiets + moet struktureren. Het is helaas maar het topje van de + ijsberg, maar ik hoop toch een idee gegeven te hebben over + de globale opbouw. Ik geef expliciet geen code omdat + praktisch blijkt dat NIEMAND daar belangstelling voor toont. + Zelfs de grootste luiaards vinden dat ze nogmaals het wiel + moeten uitvinden, en wie ben ik om dat tegen te houden. + Bovendien, zelf zou ik waarschijnlijk hetzelfde doen en de + gegeven code hooguit als voorbeeld gebruiken. + + Volgende keer komen de programmeer- en ontwikkelomgevingen + aan de beurt. Deze twee zaken zijn nl. innig verweven, en + dat is iets om terdege rekening mee te houden. + + Tot de volgende keer! + + Alex van der Wal diff --git a/sunrise_special/5/Spelontwerp 2.md b/sunrise_special/5/Spelontwerp 2.md new file mode 100644 index 0000000..8d9a267 --- /dev/null +++ b/sunrise_special/5/Spelontwerp 2.md @@ -0,0 +1,162 @@ + S P E L O N T W E R P 2 ? + + + Ongeveer een week na het uitbrengen van een Sunrise Special + breekt bij ons thuis de hel los. De brievenbus heeft dan + plotseling last van chronische indigestie. Zozeer zelfs dat + de postbode speciaal met de wagen langs komt om de fanmail + in bulk af te leveren. Nog dramatischer zijn de taferelen + bij onze onrechtmatig gedigitaliseerde hoofdredacteur. Bij + hem wordt de fanmail op dergelijke dagen op pallets + aangeleverd. Dit nadat een dozijn postbodes hernia's hebben + opgelopen bij het afleveren van postzakken lofbetuigingen. + Bij deze wil ik (ook namens Kasper) al mijn fans bedanken + voor de vage bijschriften op mijn girorekening alsmede voor + de overvloedige huwelijksaanzoeken?? [Nvdr. Zoveel + vrouwelijke of (XOR) homofiele MSX'ers zijn er toch niet?] + + U ziet, enig cynisme is ons niet vreemd. Zelden of nooit + komt er ook maar ��n letter commentaar (positief of + negatief) op de door ons gegenereerde technische + computerromans. Je hebt meer kans dat je met je ogen dicht + intelligent leven in de ruimte ontdekt dan dat er ook maar + een vleugje van een reactie waar te nemen is na de produktie + van een SRS. + + Schertste daarom ook mijn verbazing toen ik een poos geleden + plotseling wel enthousiaste mensen op mijn stoep vond die + graag wilden dat ik meer over een bepaald onderwerp zou + schrijven. Het ging daarbij over een vermeende serie die ik + zou gaan maken met als thema: "het ontwerpen van een spel". + + Dat onderwerp had ik in een opwelling eens bedacht, en onder + het motto 'It seemed like a good idea at the time' ben ik + toen als een bezetene aan een 20 delige cursus begonnen. + Veel verder dan deel 1 ben ik echter nooit gekomen. De reden + daarvoor was dat alhoewel ik me wel een voorstelling kon + maken over hoe je zoiets aanpakt ik er nog geen serieuze + praktijkervaring in had. Feitelijk stond ik jullie dus de + les te leren over een onderwerp waar ik zelf niets van af + wist. Zelfs ik begrijp dat zoiets voorbestemd is om fout te + gaan en daarom heb ik toen besloten om met die onzin op te + houden. + + Heden doet zich echter de situatie voor dat die praktische + kennis wel aanwezig is. Door de dramatische reakties op mijn + eerste poging leek het me toch een goed idee om het + verdronken kalf uit de gedempte put te graven. In + tegenstelling tot de vorige keer zullen deze + softwaretechnische verhandelingen zich in eerste instantie + niet expliciet op het ontwerpen van een spel richten, maar + meer op randvoorwaarden die van belang zijn bij de + totstandkoming van een groot software projekt. Indien ik de + maanden die zullen komen niet aan een terminale situatie + onderworpen zal worden beloof ik plechtig om mijn uiterste + best te doen om een aantal samenhangende artikelen te + schrijven. + + + W A T G A A N W E D O E N E N W A A R O M ? + + Wat ik wil doen is het behandelen van een aantal problemen + die bij ELK groot software projekt aan de orde komen. Het + beste voorbeeld daarvan is bijvoorbeeld het beheren (en + beheersen) van data. Theoretisch is het zeer eenvoudig om + een geheugen van willekeurige grootte tot de nok te vullen + met relevante data, maar praktisch kleven daar wat haken en + ogen aan. Hoe onthoud je waar welke gegevens staan en hoe + zorg je er voor dat deze gegevens elkaar niet in de weg + zitten. Ook moet je er voor zorgen dat de uiteenlopende data + op het juiste moment op de juiste plaats aanwezig zijn, wat + dan ook nog met conversieslagen gepaard gaat (zoals het + decrunchen van grafische data). + + Hopelijk zie je al dat de te behandelen problematiek niet + van toepassing is op het gemiddelde BASIC programma, maar + eerder op het soort programma dat minimaal 128 kB nodig + heeft om te kunnen werken. Waarom zou zo'n groot programma + meer problemen veroorzaken dan het gemiddelde BASIC + programma? Dat heeft te maken met het feit dat de door het + systeem in ROM aangeboden routines voor dataverwerking + plotseling niet meer voldoende blijken. In BASIC kun je + vrolijk van legio voorgebakken commando's gebruik maken, die + dan in assembly plotseling niet meer eenvoudig voorhanden + zijn. + + Samengevat kun je stellen dat het nodig is om een eigen + 'systeem' van eigen voorgebakken routines te maken om een + groot project in assembly (of elke andere taal die niet + BASIC heet) te kunnen realiseren. Het door BASIC aangeboden + systeem is simpelweg niet langer bruikbaar. + + + De (voorlopig) te behandelen onderwerpen zijn: + + - Opbouw van het eigen systeem + o een standaard filesysteem en kennismaking met een aantal + relevante programmeerstrategie�n. + o programmeer- en ontwikkelomgevingen + * keuze van en eisen aan de omgeving + * mogelijkheden van een omgeving + * algemene opbouw + o geheugen management + o interrupt management + o opbouw van het geheugen + o debugging + + Bij de behandeling van deze onderwerpen zullen + waarschijnlijk geen programma's gegeven worden. De reden + hiervoor is dat praktisch blijkt dat een te beperkt aantal + mensen dat als nuttig beschouwd. + + Mochten er nu mensen zijn die denken: "Leuk, maar ik zou + graag ook wat over onderwerp 'X' willen weten", dan kan + hij/zij dergelijke wensen bij de redactie deponeren waarna + ik ze zal behandelen. + + De eerlijkheid gebied me te zeggen dat we (= Fuzzy Logic) + reeds beschikken over een dergelijk systeem. Dit systeem + (F-KERNEL genaamd) heeft een aantal mogelijkheden die het + uitermate geschikt maakt om bijv. een RPG mee te maken. Het + systeem gaat zo ver dat op de BDOS na ALLE funkties van de + MSX-BIOS zijn overgenomen. Ik vermeld het maar even om aan + te tonen dat ik niet weer uit mijn nek sta te zwammen + (alhoewel?) [Nvdr. Who cares? Nek-zwammen kan ook heel + interessant zijn!]. + + + T O T S L O T + + H�t grote voordeel van zo'n eigen systeem is dat het (indien + goed en doordacht ontworpen) herbruikbaar is voor van alles + en nog wat. Zodra je je eerste spel af hebt met zo'n systeem + is het volgende een makkie omdat je al een scala van + handige, snelle, ge�ntegreerde en bij de gebruiker bekende + routines hebt die veel 'dom' werk uit handen nemen. + Natuurlijk gaat het niet alleen om spellen, maar ook + utility's, muziekprogramma's en noem ze maar op kunnen met + dergelijke systemen gemaakt worden. De routines die + onderdeel maken van dat systeem moet je zien als een + aanvulling op het Operating System van je computer. De + routines die er in komen zijn de routines die JIJ makkelijk + in het gebruik vindt en die je vaak gebruikt. Samengevat kan + je zeggen dat een vast eigen systeem ervoor zorgt dat je + voor elk project niet opnieuw het wiel hoeft uit te vinden. + + De ge�nteresseerden kunnen hun hart nu ophalen door deel 1 + aan een kritisch onderzoek te onderwerpen dat ook op deze + disk aanwezig is. Bedenk echter wel dat geen commentaar van + de buitenwereld voor mij betekent dat er blijkbaar geen + animo voor dit onderwerp is. Ik ben voor veel zaken te + porren, maar lullen tegen spreekwoordelijke muren is daar + niet een onderdeel van. (Gek toch dat de Special zoveel + leden heeft, maar dat die nooit wat van zich laten horen.) + Wat ik persoonlijk erg leuk zou vinden is als bv. de makers + van D.A.S.S., Giana Sisters, Pumpkin Adventure of andere + professionele spellen of andere soorten programma's ook eens + iets over de door hun gehanteerde systemen zouden willen + melden. + + Voor nu, veel plezier en keep on MSX'ing + + Alex van der Wal diff --git a/sunrise_special/5/Sprites in ML deel 2.md b/sunrise_special/5/Sprites in ML deel 2.md new file mode 100644 index 0000000..c72c330 --- /dev/null +++ b/sunrise_special/5/Sprites in ML deel 2.md @@ -0,0 +1,273 @@ + S P R I T E S I N M L 2 + + + + S P R I T E S I N D E P R A K T I J K + + Hier dan eindelijk het vervolg van de sprite besturingen in + ML. Het eerste deel kunt u vinden op Sunrise Special #2. + Om sprites daadwerkelijk op het beeld te toveren zonder + daarbij het MSX-BIOS te gebruiken is nogal een ingewikkeld + verhaal. In deel 1 hebt u kunnen lezen over de start + adressen voor de sprite data. Om enig inzicht te krijgen in + de VDP waarden, zal ik hier een aantal zaken van ophelderen + met enkele voorbeelden. + + + S P R I T E M O D E S + + Op een MSX2 of hoger zijn er nog meer zaken, wat betreft het + zetten van een sprite, waar rekening mee moet worden + gehouden. Zoals de kleuren en speciale commando bits. Daarom + spreken we van twee sprite modes: MODE 1 (MSX1 en hoger), + MODE 2 (MSX2 en hoger). Dus een MSX2 gebruikt zowel MODE 1 + als MODE 2. MODE 2 bestaat uit alle extra MSX2 functies. + + Sprite Mode 1: Graphic 1 (screen 1) + Graphic 2 (screen 2) + Multi colour (screen 3) + Max. sprites op 1 horizontale as: 4 + Sprite Mode 2: Graphic 3 (screen 4) + Graphic 4 (screen 5) + Graphic 5 (screen 6) + Graphic 6 (screen 7) + Graphic 7 (screen 8) + Max. sprites op 1 horizontale as: 8 + + + I N S T A L L E R E N V A N S P R I T E S + + Om sprites op het scherm te toveren, moeten eerst de + volgende register worden beschreven: + + Noot: Registers worden afgekord met "r# xx", hiermee worden + de registers aangeduid zoals ze in ML worden gebruikt. Dus + denkt er om MSX2 registers worden in BASIC 1 verhoogd. Dus: + VDP(12)=r#11!) + + b7 b6 b5 b4 b3 b2 b1 b0 + r# 1 x x x x x x SZ EXP(/MAG) (mode 1) + r# 8 x x x x x x SPD x (mode 1) + + SZ: SiZe. Grootte (0:8x8, 1:16x16) + EXP: EXPanded. Vergroting (0:normaal, 1:vergroot) + SPD: SPrite Display. Weergave (0:AAN, 1:UIT) + + Voorbeeld: + VDP(1)=VDP(1) and &B11111100 or &B00000010 + VDP(8)=VDP(8) or &B00000010 + + De sprite grootte is hier: 16x16 normaal (r#1). De sprites + worden zichtbaar op het scherm (r#8). + + + N O G M A A L S D E S P R I T E A D R E S S E N + + (zie ook deel 1) + + De volgende VDP registers worden hiervoor gebruikt: + + b7 b6 b5 b4 b3 b2 b1 b0 + r# 5 D14 D13 D12 D11 D10 1 1 1 (mode 1) + r#11 0 0 0 0 0 0 D16 D15 (mode 2) + r# 6 0 0 E16 E15 E14 E13 E12 E11 (mode 1) + + D10-D16: VRAM-adres voor spritekleur- en attribute tabellen. + E16-E11: VRAM-adres voor spritepatroon tabel. + + N.B. D10-D14: VRAM lijn adres + D15/D16: VRAM page nr. + E11-E14: VRAM lijn adres + E15/E16: VRAM page nr. + + Een beschrijving van de registers: + + r# 5 en r#11 vormen samen het adres waar de kleur- en + positie tabellen van de sprites. Bits 0-2 moeten altijd hoog + zijn. Bits 3-7 vormen het lijn adres van de kleur tabel. + Adres berekening: start-lijn * 128 or &H07. + + De startlijn is altijd in stappen van 8, dus kunnen er + feitelijk maar 32 verschillende waarden worden opgegeven. + + Voorbeeld: + + Stel we willen de sprite kleur data op Page 1, lijn 200 + plaatsten, dan worden r#5 en r#11: + r# 5, &HCF (200 or 7) + r#11, &H01 + + Hierbij is het kleur tabel adres bekend: 200x128 or 7=&H6400 + Het positie tabel adres: kleur tabel adres + &H0200 = &H6600 + + Standaard zijn deze registers gevuld met de volgende + waardes: + + r# 5, &B11101111/&HEF (VRAM adres: &H7400) + r#11, &B00000000/&H00 (VRAM page: 0) + + + r# 6 bevat het adres waar de patroon tabellen van de + sprites. Bits 0-3 vormen het lijn adres van de patroon + tabel. + Adres berekening: start-lijn * 128 * 16. De startlijn is + altijd in stappen van 16, dus kunnen er maar 16 + verschillende waarden worden opgegeven. Bits 4/5 bevatten + het pagina nummer. + + Voorbeeld: + Stel we willen de sprite patroon data op Page 2, lijn 32 + plaatsen, dan worden r#6: + r# 6, &H22 (32/2 or &H20) + (LSB: adres, MSB: page) + + Hierbij is de patroon tabel adres bekend: + 32*16+&H8000=&H8200. + De tabel bevindt zich boven de 32 kB (page1) dus moeten we + er &H8000 (=16 kB) bij optellen. + (als r#6>31 dan bovenste 64 kB VRAM.) + + Standaard is dit register gevuld met de volgende waarde: + r# 6, &B00001111/&H0F (VRAM adres: &H7800, page: 0) + + Het leuke van het kunnen verandereren van de sprite adressen + is dat je zonder alle sprite data hoeft te veranderen, toch + in 1 keer alle sprites kunt veranderen. + + + P L A A T S E N V A N S P R I T E S + + De sprite attribute tabel bevat de weergave waarden van de + sprites. Elke sprite wordt weergeven op 1 van de 32 "sprite + vlakken". De sprite waarden voor elk vlak bestaat uit vier + bytes. Het start adres hiervan wordt gezet door r#5 en r#11 + te beschrijven (VRAM adres: r#5/r#11 + &h0200). + + De vier bytes bevatten de volgende informatie voor 1 sprite + vlak: + +0 Y-positie De verticale positie van een sprite wordt + verhoogd met 1. Dus de werkelijk waarde die + moet worden geschreven is Y-1. Door deze + waarde op 208 (mode 1) of 216 (mode 2) te + zetten, wordt de sprite niet zichtbaar op + het scherm. + +1 X-positie Horizontale positie. Kan "slechts" 256 + waarde bevatten, dus in een hogere resolutie + (bijv. screen 7) zal de sprite altijd een + even waarde krijgen. + +2 Sprite nr. Bevat het sprite patroon, die moet worden + weer gegeven op dit vlak. + +3 Kleur Bevat de kleur van de hele sprite in sprite + Mode 1. Als er in Mode 2 wordt gewerkt, is + deze waarden onbelangrijk. Door het EC bit + (bit 7) hoog te zetten, wordt de sprite 32 + pixels naar links geschoven. + + Let op! deze waarden zijn bedoeld voor het sprite vlak. + Er zijn 32 vlakken, dus de totale lengte van de attribute + tabel is: 32 * 4 = 128 bytes. + + Voorbeeld: (8x8 sprites, niet vergroot, mode 1) + + We willen sprite 7 op vlak 11 plaatsen, met als positie + (40,50), en de kleur is 9. Eerst moeten we weten naar welk + attribute-adres we willen schrijven. We gebruiken vlak 11, + dus: 11 * 4 = 44. We weten het start adres al, door r#5/r#11 + te lezen. Dit is bijvoorbeeld: &H7600. + + Het schrijf adres wordt dan: &H7600 + 44 = &h762C. + Vervolgens beschrijven we de volgende VRAM adressen: + + &H762C+0, 50-1 (Y-1) + +1, 40 (X) + +2, 7 (nr) + +3, 9 (kleur) + + Door het EC bit te zetten wordt de sprite 32 pixels naar + links verplaatst. Het nut hiervan is dat deze sprite nu ook + pixel voor pixel aan de linker kant van het scherm kan + verdwijnen. Dat deze waarde 32 is, komt omdat een sprite + 16x16 vergroot kan wezen. Deze wordt dan immers 32x32 groot. + Ook deze sprite moet pixel voor pixel kunnen verdwijnen. + + Om een sprite daadwerkelijk op het scherm te kunnen + plaatsen, moeten er met nog een aantal zaken rekening worden + gehouden. Een van die zaken is de grootte van de sprite + (16x16). + + Als er voor 8x8 sprites wordt gekozen, levert dit geen + problemen op. Echter het gebruik van 16x16 sprites is iets + ingewikkelder. Om een 16x16 sprite te plaatsen, worden er + eigenlijk 4 (8x8) sprites geplaatst. Het totaal patroon ziet + er als volgt uit: + + X + Y +------++------+ + | spr || spr | + | +0 || +2 | + +------++------+ + | spr || spr | + | +1 || +3 | + +------++------+ + + Dus het totaal oppervlak wordt aangevuld met de 3 volgende + sprites. + Voorbeeld: (16x16 sprites, niet vergroot) + sprite patroon 3 moet worden geplaats op (10,20). + De eerste (8x8) sprite wordt dan: 3 * 4 = 12. + de opbouw wordt dan als volgt: + X=10 + Y=20 +--------------++--------------+ + |spr.12 (10,20)||spr.14 (16,20)| + +--------------++--------------+ + |spr.13 (10,36)||spr.15 (16,36)| + +--------------++--------------+ + + Om een 16x16 sprite te maken kun je dus net zo goed zelf 4 + (8x8) sprites plaatsen. Echter, 16x16 sprites hebben een + voordeel dat je maar een keer een X en een Y hoeft op te + geven, want de VDP regelt zelft de andere 3 (8x8) sprites. + + Om nu een (16x16) sprite te zetten, moet men er dus rekening + met het volgende houden: Het sprite nummer dat wordt + opgegeven moet uit stappen van 4 bestaan. Dus 0, 4, 8 etc. + + Wordt er bijvoorbeeld toch sprite 3 opgegeven, dan wordt dit + sprite patroon 0, en worden 8x8-sprites 0, 1, 2 en 3 + geplaatst. + + Bij vullen van de attribute tabel moet hier ook rekening mee + worden gehouden. Immers de 3 opvolgende sprite vlakken + worden ook gebruikt. Er zijn nus feitelijk 32/4=8 sprite + vlakken, waardoor er maar 8 sprites kunnen worden vertoond. + Dus om een sprite te zetten, wordt het adres van deze tabel + als volgt berekend: + + VRAM adres van r#5/r#11 + vlaknr * 4 * 4. + + De laatste vermenigvuldiging met 4 zorgt er voor dat de 3 + volgende vlakken worden overgeslagen, deze worden immers + automatisch door de VDP gevuld. Het vergroten van een sprite + (EXP) heeft geen gevolgen voor het berekenen van de + attribute tabellen. + + Voorbeeld: (16x16, vergroot (=32x32), mode 1) + + We willen een (16x16) sprite op vlak 3 plaatsen. X=132, + Y=40, sprite nr=0, kleur=7. De sprite moet 32 pixels naar + links worden verschoven. r#5/r#11= &H7600 + + Attribute adres: &h7600 + 3 * 4 * 4 = &H7630. + + &h7630+0, 40-1 (Y-1) + +1, 132 (X) + +2, 12 (nr: 3*4) + +3, &H87 (kleur + EC=1) + + Wat betreft het plaatsen van een sprite, moet er nu + voldoende voer zijn geleverd. Om het hele sprite verhaal af + te maken, wil ik volgende keer de aandacht richten op de + sprite botsingen (mode 1 �n 2), en de kleurcodes bij sprite + mode 2. Tot een volgende keer! + + Roman van der Meulen diff --git a/sunrise_special/5/To.md b/sunrise_special/5/To.md new file mode 100644 index 0000000..a37e810 --- /dev/null +++ b/sunrise_special/5/To.md @@ -0,0 +1,141 @@ + T O + + + Op deze disk staan twee versies van TO: TO van Fokke Post en + een C-versie van TO uit Itali�, aangepast door Pierre + Gielen. Omdat de Italiaanse TO meerdere drives aankan, en + dus meer geschikt is voor HD-gebruikers, staat hier de + handleiding daarvan. + + De hier besproken TO staat op de disk onder de naam + TO12MSX.PMA en de Fokke-versie onder de naam TO.PMA. + + Inmiddels weet ik wel al dat Fokke zijn TO aangepast heeft + voor meerdere drives, maar die versie heb ik nog niet + gezien/in bezit. Volgende keer maar weer... + + Kasper Souren + + + T O 1 2 . C O M + + TO is een handig programma dat er al lang voor MSX-DOS 2 had + moeten zijn. Met TO kun je rechtstreeks naar een directory + springen. Stel, je hebt de volgende indeling op je harddisk: + + + B:\---- C ---- HITEC ---- SYSTEM ---- LIB + | | | + | | -------- SOURCE + | | + | ------- TEMP + | + ----- PROGRAM + | + ----- STANDARD + + + ... en je wilt naar de directory LIB. Dan moet je onder + MSX-DOS 2 intypen: + + CD \C\HITEC\SYSTEM\LIB + + + Dat is nogal een hoop type werk. Afgezien daarvan moet je + het exacte pad naar de gewenste directory kennen. Heb je een + beetje veel directory's, dan wordt dat al snel moeilijk. Als + je TO.COM hebt, en je wilt naar de directory LIB, dan typ je + (waar je je ook bevindt) eenvoudig in: + + TO LIB + + + Dat werkt als volgt: TO gebruikt een bestand waarin de + complete directory-tree is opgeslagen: TREEINFO.NCD (dit + stamt van de PC-utility Norton Commander). Kan TO deze file + niet vinden, dan maakt hij hem zelf. + + + M E E R ! + + Maar TO kan meer! Als je niet meer precies weet of de + directory die je zoekt LIB of LIBS heette, maakt dat niet + uit. Dan zoek je gewoon naar LIB, of LI, en TO springt naar + de directory met de naam die met die letters begint. Zijn er + meer directory's die aan de specificatie voldoen, dan krijg + je de keuze. Bijvoorbeeld: + + TO S + + + En TO komt op de proppen met de volgende melding: + + Please choose one or ESC to abort: + + 1 \c\hitec\system + 2 \c\hitec\system\source + 3 \c\standard + + Met een enkele toetsdruk kun je dan je keuze maken. Als je + niet weet met welke letters de naam begint, kun je op het + einde van de naam zoeken door een * voor de naam te zetten. + Bijvoorbeeld: je wilt naar de directory STANDARD, maar je + weet niet zeker of je die STANDARD of STANDAARD hebt + genoemd. Dan typ je in: + + TO *ARD + + + ...en TO springt naar de directory \C\STANDARD. + + + M E E R D E R E D R I V E S + + TO kan ook met meerdere drives werken. Die kun je opgeven in + de volgorde waarin op de verschillende drives moet worden + gezocht. Bijvoorbeeld + + TO -dABHC SYSTEM + + ...zoekt achtereenvolgens op de drives A:,B:,H:, en C: naar + de directory SYSTEM. Omdat dit nogal veel typwerk is, kun je + het environment item DRIVES specificeren, als volgt: + + SET DRIVES=ABHC + + Natuurlijk kun je deze regel het beste in de AUTOEXEC.BAT + opnemen. Als DRIVES zoals hierboven is gedefinieerd, heeft + dat hetzelfde effect als de drives in de commandline + opgeven. + + N.B. Je hoeft het in de commandline niet bij 1 directory te + laten. Je kunt er tot 10 opgeven, en daarna een keuze maken. + + + O P M E R K I N G E N + + - Record directory, zoals in TO.DOC beschreven, werkt niet. + Gebruik hiervoor mijn programma PPDIR (PPDIR PUSH, PPDIR + POP). (Zie een vorige Sunrise Magazine.) + + - De commandline switch -B maakt een nieuwe TREEINFO.NCD. + Gebruik deze mogelijkheid als je nieuwe directory's hebt + gemaakt of oude gewist. Let op: bij deze optie loopt TO + alle met (-D of DRIVES=) ingestelde drives af. + + - TO gebruikt geen TO.INI zoals in TO.DOC beschreven. Het + environment item DRIVES (natuurlijk veel sneller!) is + hiervoor in de plaats gekomen. + + - TO is en blijft een gratis programma. Als het je bevalt, + stuur dan een ansichtkaart naar: + + Andrea Steffanoni + Via Cherubini, 6 + 20145 Milano + Italy + + Vermeld er wel bij dat je een conversie naar MSX-DOS + gebruikt. + + Pierre Gielen diff --git a/sunrise_special/5/Turbo Loader.md b/sunrise_special/5/Turbo Loader.md new file mode 100644 index 0000000..4979a0b --- /dev/null +++ b/sunrise_special/5/Turbo Loader.md @@ -0,0 +1,305 @@ + T U R B O L O A D E R + + + Demo's op de Picturedisk bestaan vaak uit een groot aantal + files, en omdat de BDOS voor elke file opnieuw in de + directory en FAT moet gaan kijken waar de file precies + staat, duurt het laden relatief lang. + + De laadtijd kan enorm worden verkocht door voor de demo een + zogenaamde "turbo loader" te maken. Je zet dan alle files + achter elkaar in ��n grote file, en je maakt een klein ML + programmaatje dat alles inlaadt en op de juiste plek zet en + vervolgens het hoofdprogramma start. + + De naam "turbo" is zeker niet ten onrechte, want het laden + gaat zo veel en veel sneller dan wanneer alle files apart + moeten worden geladen. De enige manier om nog sneller te + laden is door alles op sector te zetten zoals ook bij de + Special wordt gedaan met de teksten, muziek en graphics, + maar dat is voor de Picturedisk erg onhandig. + + Ik zal het principe van de turbo loader, heel toepasselijk, + uitleggen aan de hand van de Witch's Revenge promo die ik + voor Sunrise Picturedisk #9 had gemaakt. + + + P L A K K E N + + We gaan de files met het DOS2 commando CONCAT aan elkaar + plakken. Zet eerst de benodigde files netjes bij elkaar op + een disk en geef ze zulke namen dat je ze met ��n filenaam + met wildcards exclusief kunt beschrijven. + + Dit klinkt misschien moeilijk, maar dat valt reuze mee. Noem + de files bijvoorbeeld DEMO.MBM, DEMO.MBK, DEMO.SC5, etc. Met + DEMO.* heb je dan alle files te pakken. Met "exclusief" + bedoel ik dat er geen andere files op de disk staan die niet + bij de demo horen maar die wel aan DEMO.* voldoen. + + In het voorbeeld had ik de volgende files: + + DRUMKIT DAT 5760 03-11-93 20:21 + GFX1 DAT 13568 03-11-93 20:18 + GFX2 DAT 12672 03-11-93 20:19 + MUSIC DAT 2304 03-11-93 20:22 + TEXT DAT 2048 04-11-93 16:49 + MBREPLAY DAT 4608 18-08-93 11:32 + + + We plakken deze files nu aan elkaar tot ��n grote file + WRPROMO.ALL van ca. 40 kB met het volgende commando (onder + DOS2!): + + CONCAT /B *.DAT WRPROMO.ALL + + Nu zien we de reden waarom ik de files zo heb hernoemd dat + ze met *.DAT beschreven kunnen worden, want met de + oorspronkelijke filenamen had het er zo uitgezien: + + CONCAT /B DRUMKIT.MBK + GFX1.SC7 + GFX2.SC7 + ... + + De /B is nodig om de files binair achterelkaar te zetten, + als je dat weglaat dan worden de files bij de eerste ^Z + afgekapt en dat is natuurlijk niet de bedoeling. + + Het is zometeen belangrijk dat je de volgorde en de lengtes + van de files bij de hand hebt, dit kan (wederom onder DOS2) + heel makkelijk met: + + DIR *.DAT > DIR.TXT + + In DIR.TXT staat nu de directory van de .DAT files. Met + behulp van deze file gaan we nu een ML progje schrijven dat + WRPROMO.ALL inleest. + + + D E L O A D E R + + Om de file in te laden gebruiken we de BDOS. We defini�ren + nu eerst een aantal functienummers en het BDOS aanroepadres: + + + BDOS: EQU &HF37D + SETDMA: EQU &H1A + OPEN: EQU &H0F + READ: EQU &H27 + + + Een BDOS functie kan worden aangeroepen door het + functienummer in register C te zetten en vervolgens het + adres &HF37D aan te roepen. + + We moeten nu eerst de file WRPROMO.ALL openen. We gebruiken + hiervoor de BDOS functie OPEN, waarbij DE naar het FCB moet + wijzen. FCB staat voor File Control Block. Een FCB is een + blokje van 37 bytes, dat als volgt is opgebouwd: + + FCB+0 drive (0 = default, 1 = A:, 2 = B:, etc.) + FCB+1 filenaam (8 karakters) + FCB+9 extensie (3 karakters) + FCB+14 record size (16 bits waarde) + FCB+33 random record (32 bits waarde) + + Er staat nog meer informatie in, maar die is voor ons nu + niet interessant. In de ML source ziet de FCB er als volgt + uit: + + + FCB: DB 0 + DM "WRPROMO ALL" + DB 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + DB 0,0,0,0,0,0,0,0,0,0 + + + Het openen van de file gaat nu als volgt: + + + LD C,OPEN ; open de file + LD DE,FCB + CALL BDOS + LD HL,1 + LD (FCB+14),HL ; record size + + + De recordsize wordt op 1 byte gezet, zo kunnen we elk + willekeurig stuk van de file inlezen. Door de waarde van + "random record" te veranderen kunnen we de diverse gedeeltes + van WRPROMO.ALL in een willekeurige volgorde inlezen, maar + het is het makkelijkste om het op de volgorde te doen waarin + ze in de file staan, want dan gaat het vanzelf goed. + + De eerste file is de drumkit, deze file is 5760 bytes lang. + Dit is een ingekorte drumkit van MoonBlaster, ik heb de rest + gewoon "weggegooid" omdat dat niet werd gebruikt. + + De eerste 56 bytes bevatten de sample adressen, die straks + in de MoonBlaster replayer moeten worden ingevuld. We laden + eerst deze 56 bytes in en bewaren ze zolang in een + buffertje. + + + LD DE,SMPBUF ; sample adressen + LD C,SETDMA + CALL BDOS + LD HL,56 ; aantal te lezen bytes + LD DE,FCB + LD C,READ + CALL BDOS + + + De functie SETDMA stelt het adres in waar de data naartoe + moet, dit adres moet in DE staan. De BDOS functie &H27 die + we hier gebruiken heeft als invoer HL en DE nodig. DE wijst + weer naar het FCB en in HL moet het aantal bytes staan. + + Nu gaan we de rest van de samplekit inladen. Omdat we de + MoonBlaster replayer nog niet hebben ingeladen, zetten we + die zolang op mapper page 2. + + + LD A,2 + OUT (&HFE),A + + LD DE,&H8000 ; samplekit + LD C,SETDMA + CALL BDOS + LD HL,5760-56 + LD DE,FCB + LD C,READ + CALL BDOS + + + Dit gaat weer precies hetzelfde. Nu zijn de graphics aan de + beurt. Ik gebruik mapper page 3 als laadbuffer. De lengte + van de eerste file met graphics is 13568 bytes, zo kunnen we + in de directory zien. + + + LD A,3 + OUT (&HFE),A + + LD DE,&H8000 ; gfx1 + LD C,SETDMA + CALL BDOS + LD HL,13568 + LD DE,FCB + LD C,READ + CALL BDOS + LD HL,0 + CALL DCRNCH + + + De graphics waren gecruncht en worden met de routine DCRNCH + (die ik hier niet bij heb gezet) gedecruncht naar VRAM-adres + &H00000. Het inladen van het tweede gedeelte van de graphics + gaat net zo: + + + LD DE,&H8000 ; gfx2 + LD C,SETDMA + CALL BDOS + LD HL,12672 + LD DE,FCB + LD C,READ + CALL BDOS + LD HL,&H8000 + CALL DCRNCH + + + Deze graphics worden naar adres &H08000 gedecruncht. Nu + laden we het muziekje in, dat op adres &H8000 in mapper page + 3 moet staan (mapper page 3 was al geselecteerd). + + + LD DE,&H8000 ; muziek + LD C,SETDMA + CALL BDOS + LD HL,2304 + LD DE,FCB + LD C,READ + CALL BDOS + + + Nu is de tekst aan de beurt. Eerst wordt de mapper + teruggezet. + + + LD A,1 + OUT (&HFE),A + + LD DE,&HB000 ; tekst + LD C,SETDMA + CALL BDOS + LD HL,2048 + LD DE,FCB + LD C,READ + CALL BDOS + + + Tot slot wordt de MoonBlaster replayer ingeladen, die in dit + geval op adres &HC800 begint. + + + LD DE,&HC800 ; MoonBlaster replay + LD C,SETDMA + CALL BDOS + LD HL,4608 + LD DE,FCB + LD C,READ + CALL BDOS + + + Nu is de MoonBlaster replayer ingeladen en kunnen de + sampleadressen erin worden gezet en de samples kunnen naar + de MSX-AUDIO worden gekopieerd. + + + LD A,2 + OUT (&HFE),A + CALL MOVSMP + LD A,1 + OUT (&HFE),A + + LD HL,SMPBUF + LD DE,SMPADR + LD BC,56 + LDIR ; zet sampleadressen in + ; replayer + + + In dit geval had ik de hoofdroutine hier direct achter + gezet, eventueel kan die natuurlijk ook in de grote file + worden gezet. Tot slot moeten we nog even ruimte reserveren + voor de tijdelijke opslag van de sample adressen: + + + SMPBUF: DS 56 ; buffer sample adressen + + + Zoals je ziet is het laden vanuit ML dus helemaal niet + moeilijk! Nu nog even iets over ruimtebesparing. + + + C R U N C H E N + + De redactie van de Picturedisk is altijd zeer blij als de + demo's zo klein mogelijk zijn, want dan past er des te meer + op de Picturedisk. Als er met losse files wordt gewerkt kan + de redactie meestal zelf de graphics wel crunchen als dat + nog niet gedaan is, maar met een turbo loader is dat + natuurlijk onbegonnen werk. Zorg er dus altijd voor dat de + graphics worden gecruncht voordat je ze in de grote file + zet! + + + T E N S L O T T E + + Als resultaat krijg je een file WRPROMO.BIN met de loader en + een file WRPROMO.ALL met alle muziek, graphics, etc. Het + laadt niet alleen sneller maar is ook nog een stuk + overzichtelijker! Ik roep dan ook iedereen die demo's voor + de Picturedisk maakt om ze in de vorm van een turbo loader + aan te leveren! + + Stefan Boer diff --git a/sunrise_special/5/Uncall.md b/sunrise_special/5/Uncall.md new file mode 100644 index 0000000..4a98103 --- /dev/null +++ b/sunrise_special/5/Uncall.md @@ -0,0 +1,23 @@ + U N C A L L + + + Een uitstapje naar MSX-DOS zorgt ervoor dat als je in BASIC + een programma hebt geladen, dat zichzelf in page 1 + (#4000-#7FFF) van het RAM plaatst en gebruik maakt van een + CALL commando, de computer blijft hangen bij nog eens een + CALL commando. + + UNCALL is hier de oplossing voor. UNCALL zorgt ervoor dat de + data, die ervoor zorgt, dat er door de computer naar page 1 + van het RAM plaatst, wordt weggehaald. Als je UNCALL.COM dus + aanroept in REBOOT.BAT, gaat het dus niet meer fout. + + Omdat je zonder harddisk toch niet vaak naar MSX-DOS + teruggaat, en je zeker geen plaats hebt voor kleine + utility's die niet echt nodig zijn, heb ik dit stukje toch + maar in de harddisk rubriek geplaatst. + + UNCALL is overigens geschreven door Roderik Muit van + FCS-BBS: 01859-13957, 24 uur per dag. + + Kasper Souren diff --git a/sunrise_special/5/VDP Cursus 7.md b/sunrise_special/5/VDP Cursus 7.md new file mode 100644 index 0000000..5e937b8 --- /dev/null +++ b/sunrise_special/5/VDP Cursus 7.md @@ -0,0 +1,421 @@ + V D P C U R S U S 7 + + + + I N L E I D I N G + + In het alweer zevende deel van deze zeer populaire cursus + wordt een begin gemaakt met het behandelen van de schermmodi + van de V9938 en de opslag in het VRAM. In deel 8 volgt de + rest van dit overzicht. Als we dat achter de rug hebben, + hebben we alle theorie gehad en kunnen we beginnen met het + interessantste gedeelte: de praktijkvoorbeelden. Vele + nuttige, leerzame of gewoon leuke routines zullen de revue + passeren. + + Maar eerst moeten we nog even het laatste stukje theorie + behandelen. De MSX2+ schermen worden (helaas) erg weinig + gebruikt en ik heb ze al vele malen eerder besproken, dus + die zal ik hier buiten beschouwing laten. + + + S C H E R M M O D I + + Hoeveel schermmodi (schermsoorten) heeft een MSX2 volgens u? + Een heleboel MSX'ers zullen op deze vraag een verkeerd + antwoord geven, namelijk 9 of zelfs 8! Het juiste antwoord + is 10! Een overzicht: + + BASIC: VDP: Afkorting: + -------------------------------------------------- + SCREEN 0: WIDTH 1-40 TEXT 1 T1 + SCREEN 0: WIDTH 41-80 TEXT 2 T2 + SCREEN 3 MULTI-COLOR MC + SCREEN 1 GRAPHIC 1 G1 + SCREEN 2 GRAPHIC 2 G2 + SCREEN 4 GRAPHIC 3 G3 + SCREEN 5 GRAPHIC 4 G4 + SCREEN 6 GRAPHIC 5 G5 + SCREEN 7 GRAPHIC 6 G6 + SCREEN 8 GRAPHIC 7 G7 + --------------------------------------------------- + + Vanaf nu zal ik alle schermen benoemen volgens de afkorting + zoals die in de derde kolom staat. Per scherm zal ik nu een + overzicht geven van de mogelijkheden en hoe dat in het VRAM + is opgeslagen. Deze keer komen T1, T2 en MC aan bod. De + G-modes komen in deel 8 aan de beurt. + + + T E X T 1 + + Formaat: 24 regels van 40 kolommen tekst + Kleuren: voorgrond- en achtergrondkleur kunnen worden + gekozen uit een palet van 512 + Karakters: 256 karakters, 6 (hor) * 8 (vert) + VRAM: karakterset 2048 bytes (8 * 256) + scherminhoud 960 bytes (40 * 24) + + Voor het selecteren van de schermmode gebruikt de VDP de + bits M1-M5. Deze bits zijn te vinden in R#0 en R#1: + + -------------------------------------------------------- + MSB 7 6 5 4 3 2 1 0 LSB + + R#0 0 DG IE2 IE1 M5 M4 M3 0 Mode Register #0 + R#1 0 BL IE0 M1 M2 0 SI MAG Mode Register #1 + -------------------------------------------------------- + + Om TEXT 1 te krijgen moet de VDP als volgt staan ingesteld: + + M1 M2 M3 M4 M5 + T1 1 0 0 0 0 + + De karakterset staat in de zogenaamde Pattern Generator + Table. Deze tabel staat in het VRAM. Elk karakter wordt + gecodeerd door 8 bytes. Er zijn 256 karakters, genummerd van + 0 t/m 255. Het beginadres van een karakter is als volgt te + berekenen: + + + 8 * karakternummer + + Bit 0 en 1 van elke byte worden niet getoond, omdat een + karakter 6 pixels breed is in plaats van 8. Het beginadres + van de Pattern Generator Table moet in R#4 staan. De 11 + laagste bits van dit adres (bit 0 t/m 10) zijn altijd 0. + Alleen de 6 bovenste bits (bit 11 t/m 16) staan in R#4: + + --------------------------------------------------------- + MSB 7 6 5 4 3 2 1 0 LSB + + R#4 0 0 A16 A15 A14 A13 A12 A11 Pattern Generator + --------------------------------------------------------- + + In BASIC is deze waarde op te vragen c.q. te veranderen + middels BASE(2). + + Voorbeeld van de opbouw van de Pattern Generator Table: + + MSB 7 6 5 4 3 2 1 0 LSB + + 0 0 1 0 0 0 0 0 + 520 + 0 1 0 1 0 0 0 0 + 521 + 1 0 0 0 1 0 0 0 + 522 + 1 0 0 0 1 0 0 0 + 523 + 1 1 1 1 1 0 0 0 + 524 + 1 0 0 0 1 0 0 0 + 525 + 1 0 0 0 1 0 0 0 + 526 + 0 0 0 0 0 0 0 0 + 527 + + De A staat op adres 65 (ASCII van A) * 8 = 520. Een 1 + betekent dat de voorgrondkleur wordt getoond, een 0 de + achtergrondkleur. + + De Pattern Name Table geeft aan welk karakter op elke + positie van het scherm wordt getoond. Het beginadres staat + in R#2. De laagste 10 bits (bit 0 t/m 9) zijn altijd 0, de + hoogste 7 bits (10 t/m 16) staan in R#2. + + ---------------------------------------------------- + MSB 7 6 5 4 3 2 1 0 LSB + + R#2 0 A16 A15 A14 A13 A12 A11 A10 Pattern Name + ---------------------------------------------------- + + In BASIC is deze waarde op te vragen c.q. te veranderen + middels BASE(0). + + De karakternummers staan in de Pattern Name Table van links + naar rechts, van boven naar onder. Dus: + + | 0 1 2 3 ... 39 + -----+----------------------------------------------- + 0 | 0 1 2 3 39 + 1 | 40 41 42 43 79 + ... | + 23 | 920 921 922 923 959 + + Het adres behorende bij de positie (X,Y) kan als volgt + worden berekend: + + + Y * 40 + X + + De schermkleuren worden gedefinieerd met R#7. De achter- + grondkleur (A, tevens de kleur van de border) wordt bepaald + door de onderste vier bits, de voorgrondkleur (V) wordt + bepaald door de bovenste vier bits. + + -------------------------------------------------- + MSB 7 6 5 4 3 2 1 0 LSB + + R#7 V3 V2 V1 V0 A3 A2 A1 A0 Text color + -------------------------------------------------- + + + T E X T 2 + + Formaat: 24 of 26.5 regels van 80 kolommen tekst + Kleuren: voorgrond- en achtergrondkleur kunnen worden + gekozen uit een palet van 512 + Karakters: 256 karakters, 6 (hor) * 8 (vert) + VRAM: karakterset 2048 bytes (8 * 256) + 24 regels: scherminhoud 1920 bytes (80 * 24) + blinktabel 240 bytes (1920 bits) + 26.5 regels: scherminhoud 2160 bytes (80 * 27) + blinktabel 270 bytes (2160 bits) + + Om TEXT 2 te krijgen moet de VDP als volgt staan ingesteld: + + M1 M2 M3 M4 M5 + T2 1 0 0 1 0 + + Bit 7 van R#9 bepaalt het aantal regels van T2. + + ------------------------------------------------- + MSB 7 6 5 4 3 2 1 0 LSB + + R#9 LN 0 S1 S0 IL EO NT DC Mode Reg #3 + ------------------------------------------------- + + Het scherm heeft 26.5 regels als LN=1. Dit wordt niet door + BASIC ondersteund. Het kan wel gebruikt worden, maar de + regels 24-26 kunnen niet met LOCATE/PRINT commando's worden + beschreven. Van de 27ste regel (regel 26) wordt alleen de + bovenste helft weergegeven. + + De Pattern Generator Table werkt hetzelfde als bij T1. Zie + dus bij T1. + + De Pattern Name Table geeft aan welk karakter op elke + positie van het scherm wordt getoond. Het beginadres staat + in R#2. De laagste 12 bits (bit 0 t/m 11) zijn altijd 0, de + hoogste 5 bits (12 t/m 16) staan in R#2. + + ---------------------------------------------------- + MSB 7 6 5 4 3 2 1 0 LSB + + R#2 0 A16 A15 A14 A13 A12 1 1 Pattern Name + ---------------------------------------------------- + + In BASIC is deze waarde op te vragen c.q. te veranderen + middels BASE(0). Let op: in R#2 zijn bit 1 en 0 altijd 1, + maar bit 11 en bit 10 van het beginadres van de Pattern Name + Table zijn toch 0! + + De karakternummers staan in de Pattern Name Table van links + naar rechts, van boven naar onder. Dus: + + | 0 1 2 3 ... 79 + -----+----------------------------------------------- + 0 | 0 1 2 3 79 + 1 | 80 81 82 83 159 + ... | + 23 | 2080 2081 2082 2083 2159 + + Het adres behorende bij de positie (X,Y) kan als volgt + worden berekend: + + + Y * 80 + X + + + B L I N K M O D E + + Aan deze mode is al eerder aandacht besteed. Elke positie op + T2 kan in de blink-mode worden gezet. Voor elke positie is + een bit gereserveerd in de blink table. Als dit bit 1 is, is + de blink mode actief. Het startadres van de blink tabel + staat in R#3 en R#10. De bovenste acht bits staan in R#3 en + R#10, de onderste negen bits zijn altijd 0. + + -------------------------------------------------------- + MSB 7 6 5 4 3 2 1 0 LSB + + R#3 A13 A12 A11 A10 A9 1 1 1 Color table low + R#10 0 0 0 0 0 A16 A15 A14 Color table high + -------------------------------------------------------- + + Let op! In R#3 zijn de bits 0 t/m 2 altijd 1, maar bit 6 t/m + 8 van het beginadres van de blink tabel zijn toch altijd 0! + + De blinkbits staan in de Blink Tabel van links naar rechts, + van boven naar onder. + + Het adres behorende bij de positie (X,Y) kan als volgt + worden berekend: + + + Y * 10 + (X\8) + + Dit blinkbits van de posities (8,4) t/m (15,4) staan dus op + adres: + + 4 * 10 + 1 = 41 + + De waarde op adres 41 wordt dan als volgt geinterpreteerd: + + 7 6 5 4 3 2 1 0 bit + (8,4) (9,4) (10,4) (11,4) (12,4) (13,4) (14,4) (15,4) + + R#7 werkt net zoals bij T1. De blinkkleuren staan in R#12, + op dezelfde manier als bij R#7. De posities waarvan het + blink-bit 1 is, zullen beurtelings in de kleuren van R#7 en + de kleuren van R#12 worden getoond. + + Het tempo waarmee dat gebeurt staat in R#13. De tijden + kunnen worden opgegeven in ca. 1/6 seconde. De bovenste vier + bits bepalen de periode waarin de kleuren van R#12 worden + getoond, de onderste vier bits bepalen de periode waarin de + kleuren van R#7 worden getoond. + + ---------------------------------------------------- + MSB 7 6 5 4 3 2 1 0 LSB + + R#12 B3 B2 B1 B0 N3 N2 N1 N0 Blink Colour + ---------------------------------------------------- + (B=blinkkleur tijd, N=normale kleur tijd) + + + M U L T I C O L O U R + + Formaat: 48 regels van 64 blokjes van 4*4 + Kleuren: 16 kleuren uit een palet van 512 + VRAM: kleuren 2048 bytes + posities 768 bytes + Sprite: Sprite mode 1 + + Om MULTI-COLOUR te krijgen moet de VDP als volgt staan + ingesteld: + + M1 M2 M3 M4 M5 + MC 0 1 0 0 0 + + De multi-colour mode zit nogal ingewikkeld in elkaar. De + multi-colour mode wordt heel weinig gebruikt, omdat de + graphics heel erg blokkerig zijn. Bovendien zit de opslag in + het VRAM zeer ingewikkeld in elkaar. Ik zal proberen om het + toch enigszins te verduidelijken. + + MC werkt met blokjes van 4*4 pixels. Deze 16 pixels hebben + allemaal dezelfde kleur. + + Een patroon bestaat in MC uit 16 blokjes, 8 hoog en 2 breed. + De patronen staan in de Pattern Generator Table. Het + beginadres is te vinden in R#4. De 11 laagste bits van dit + adres (bit 0 t/m 10) zijn altijd 0. Alleen de 6 bovenste + bits (bit 11 t/m 16) staan in R#4: + + --------------------------------------------------------- + MSB 7 6 5 4 3 2 1 0 LSB + + R#4 0 0 A16 A15 A14 A13 A12 A11 Pattern Generator + --------------------------------------------------------- + + In BASIC is deze waarde op te vragen c.q. te veranderen + middels BASE(17). + + Er zijn 256 patronen (genummerd van #0 t/m #255), die elk 8 + bytes in beslag nemen. De kleuren van de twee blokjes naast + elkaar in het patroon staan steeds in 1 byte, die van het + linkse blokje in de 4 hoogste bits en die van het rechtse + blokje in de 4 laagste bits. We stellen een patroon als + volgt voor: + + AB + CD + EF + GH + IJ + KL + MN + OP + + Elke letter staat voor een blokje. Dit patroon staat dan als + volgt in het VRAM: + + = + 8 * + + MSB 7 6 5 4 3 2 1 0 LSB + + +0 A3 A2 A1 A0 B3 B2 B1 B0 + +1 C3 C2 C1 C0 D3 D2 D1 D0 + +2 E3 E2 E1 E0 F3 F2 F1 F0 + +3 etc. + +7 O3 O2 O1 O0 P3 P2 P1 P0 + + Voor elk blokje zijn telkens vier bits gereserveerd, waarin + het kleurnummer (0-15) staat. + + Voor de Pattern Name Table verdelen wij het scherm in 768 + posities, 32 horizontaal en 24 verticaal. Verder werkt dit + weer net zo als bij de vorige modi. Het adres behorende bij + de positie (X,Y) kan als volgt worden berekend: + + + Y * 32 + X + + Het beginadres van de Pattern Name Table staat in R#2. De + laagste 10 bits (bit 0 t/m 9) zijn altijd 0, de hoogste 7 + bits (10 t/m 16) staan in R#2. + + ---------------------------------------------------- + MSB 7 6 5 4 3 2 1 0 LSB + + R#2 0 A16 A15 A14 A13 A12 A11 A10 Pattern Name + ---------------------------------------------------- + + In BASIC is deze waarde op te vragen c.q. te veranderen + middels BASE(15). + + In deze tabel staat voor elke positie welk patroon er + getoond moet worden. De Y-coordinaat van de positie bepaalt + welk gedeelte van het patroon wordt getoond. Dit gaat als + volgt: + + Y gedeelte + -------------------------------- + 00 04 08 12 16 20 ABCD + 01 05 09 13 17 21 EFGH + 02 06 10 14 18 22 IJKL + 03 07 11 15 19 23 MNOP + -------------------------------- + + Zoals u ziet is dit behoorlijk ingewikkeld. Gelukkig zal dit + scherm (zeker op een MSX2) zelden gebruikt worden. En als + het al gebruikt wordt, dan zal het vaak in BASIC zijn. En in + dat geval regelt BASIC alles voor u. + + In BASIC is de Name Table overigens zo ingevuld dat die niet + gewijzigd hoeft te worden. Daar wordt alleen de Pattern + Generator Table gewijzigd. Op de eerste 4 regels (0 t/m 3) + staan naast elkaar de patronen 0 t/m 31. Op de volgende 4 + regels de patronen 32 t/m 63, enz. Tenslotte staan op regel + 20 t/m 23 de patronen 160 t/m 191. + + De patronen 192 t/m 255 worden in BASIC dus niet gebruikt! + Dat is ook niet nodig. Rekent u even mee? 64 bij 48 blokken, + dat zijn 3072 blokken. Een patroon bevat 16 blokken, dus + 3072 / 16 = 192 patronen. + + Tot slot nog even de border kleur. Die wordt in de multi- + colour mode (en ook in alle Graphic modes) bepaald door de + vier laagste bits van R#7. De vier bovenste bits zijn niet + geldig. + + ---------------------------------------------------- + MSB 7 6 5 4 3 2 1 0 LSB + + R#7 ---ongeldig---- C3 C2 C1 C0 Border color + ---------------------------------------------------- + + De sprites zijn in het vorige deel van de VDP cursus al + behandeld. + + + T O T S L O T + + Dit was het voor deze keer. De volgende keer zullen de zeven + grafische modes worden behandeld (ja, volgens de VDP is + SCREEN 1 een grafische mode!). Experimenteert u maar eens + wat met SCREEN 3, u zult zien dat het best meevalt. + + Tot de volgende keer! + + Stefan Boer diff --git a/sunrise_special/5/VDP Cursus 8.md b/sunrise_special/5/VDP Cursus 8.md new file mode 100644 index 0000000..9785247 --- /dev/null +++ b/sunrise_special/5/VDP Cursus 8.md @@ -0,0 +1,502 @@ + V D P C U R S U S 8 + + + + I N L E I D I N G + + We zijn alweer bij het achtste deel van de nog immer + populaire VDP cursus aangeland. Zoals beloofd gaan we deze + keer verder met het behandelen van de opslag van schermen in + het VRAM. Deze keer zullen we SCREEN 1, 2 en 4 bekijken, + oftewel G1, G2 en G3. De laatste schermen van de V9938 (G4 + t/m G7) zullen in deel 9 worden besproken. + + Ik was eerst van plan om in dit deel alle Graphic Modes te + behandelen, maar toen ik met deze drie al over de 16 kB heen + zat heb ik besloten om het daar maar bij te laten. De + betekent dus even goed dat dit deel van de VDP cursus niet + in ��n keer kan worden ingeladen. Dat is de eerste keer in + de geschiedenis van de VDP cursus dat dat gebeurt! + + + G R A P H I C 1 + + Formaat: 24 regels van 32 kolommen tekst + Kleuren: 16 uit een palet van 512 + 2 kleuren per 8 karakters + Karakters: 256 karakters, 8 (hor) * 8 (vert) + VRAM: karakterset 2048 bytes (8 * 256) + scherminhoud 768 bytes (32 * 24) + kleuren 32 bytes + sprite patronen 2048 bytes (8 * 256) + sprite attr. 128 bytes (4 * 32) + Sprites: Sprite mode 1 + + Voor het selecteren van de schermmode gebruikt de VDP de + bits M1-M5. Deze bits zijn te vinden in R#0 en R#1: + + -------------------------------------------------------- + MSB 7 6 5 4 3 2 1 0 LSB + + R#0 0 DG IE2 IE1 M5 M4 M3 0 Mode Register #0 + R#1 0 BL IE0 M1 M2 0 SI MAG Mode Register #1 + -------------------------------------------------------- + + Om GRAPHIC 1 te krijgen moet de VDP als volgt staan + ingesteld: + + M1 M2 M3 M4 M5 + G1 0 0 0 0 0 + + De karakterset staat in de zogenaamde Pattern Generator + Table. Deze tabel staat in het VRAM. Elk karakter wordt + gecodeerd door 8 bytes. Er zijn 256 karakters, genummerd van + 0 t/m 255. Het beginadres van een karakter is als volgt te + berekenen: + + + 8 * karakternummer + + Het beginadres van de Pattern Generator Table moet in R#4 + staan. De 11 laagste bits van dit adres (bit 0 t/m 10) zijn + altijd 0. Alleen de 6 bovenste bits (bit 11 t/m 16) staan in + R#4: + + --------------------------------------------------------- + MSB 7 6 5 4 3 2 1 0 LSB + + R#4 0 0 A16 A15 A14 A13 A12 A11 Pattern Generator + --------------------------------------------------------- + + In BASIC is deze waarde op te vragen c.q. te veranderen + middels BASE(7). + + Voorbeeld van de opbouw van de Pattern Generator Table: + + MSB 7 6 5 4 3 2 1 0 LSB + + 0 0 1 1 1 0 0 0 + 520 + 0 1 1 0 1 1 0 0 + 521 + 1 1 0 0 0 1 1 0 + 522 + 1 1 0 0 0 1 1 0 + 523 + 1 1 1 1 1 1 1 0 + 524 + 1 1 0 0 0 1 1 0 + 525 + 1 1 0 0 0 1 1 0 + 526 + 0 0 0 0 0 0 0 0 + 527 + + De A staat op adres 65 (ASCII van A) * 8 = 520. Een 1 + betekent dat de voorgrondkleur wordt getoond, een 0 de + achtergrondkleur. + + Per groep van 8 karakters kunnen de voor- en achtergrond- + kleur worden ingesteld (kar. #0-#7, #8-#15, etc). Het + startadres van de kleurentabel wordt bepaald door de waarde + van R#3 en R#10. Alleen de hoogste 11 bits (bit 6 t/m 16) + staan in deze registers: + + -------------------------------------------------------- + MSB 7 6 5 4 3 2 1 0 LSB + + R#3 A13 A12 A11 A10 A9 A8 A7 A6 Color table low + R#10 0 0 0 0 0 A16 A15 A14 Color table high + -------------------------------------------------------- + + De kleurentabel is als volgt opgebouwd: + + MSB 7 6 5 4 3 2 1 0 LSB + + ---V--- ---A--- + 0 karakters 0-7 + ---V--- ---A--- + 1 karakters 8-15 + + ---V--- ---A--- + 31 karakters 248-255 + + Waarbij V staat voor de voorgrondkleur (0-15) en A voor de + achtergrondkleur (ook 0-15). + + De Pattern Name Table geeft aan welk karakter op elke + positie van het scherm wordt getoond. Het beginadres staat + in R#2. De laagste 10 bits (bit 0 t/m 9) zijn altijd 0, de + hoogste 7 bits (10 t/m 16) staan in R#2. + + ---------------------------------------------------- + MSB 7 6 5 4 3 2 1 0 LSB + + R#2 0 A16 A15 A14 A13 A12 A11 A10 Pattern Name + ---------------------------------------------------- + + In BASIC is deze waarde op te vragen c.q. te veranderen + middels BASE(5). + + De karakternummers staan in de Pattern Name Table van links + naar rechts, van boven naar onder. Dus: + + | 0 1 2 3 ... 31 + -----+----------------------------------------------- + 0 | 0 1 2 3 31 + 1 | 32 33 34 35 63 + ... | + 23 | 736 737 738 739 767 + + Het adres behorende bij de positie (X,Y) kan als volgt + worden berekend: + + + Y * 32 + X + + De borderkleur wordt gedefinieerd met R#7, en wel door de + vier minst significante bits. + + ---------------------------------------------------- + MSB 7 6 5 4 3 2 1 0 LSB + + R#7 --ongeldig--- B3 B2 B1 B0 Border color + ---------------------------------------------------- + + Het tweede gedeelte, met G2 en G3, kunt u in het submenu + vinden. + + Stefan Boer + + + + - TWEEDE GEDEELTE - + + V D P C U R S U S 8 + + + + G R A P H I C 2 E N 3 + + Deze schermmodes (SCREEN 2 en 4) komen zoveel overeen, dat + ik ze hier in ��n keer bespreek. + + Formaat: 24 regels van 32 patronen + Kleuren: per 8 pixels 2 van de 16 kleuren + deze 16 kleuren uit een palet van 512 + Patronen: 3*256 patronen, 8 (hor) * 8 (vert) + VRAM: patronen 6144 bytes (8 * 3 * 256) + kleuren 6144 bytes (8 * 3 * 256) + scherminhoud 768 bytes (24 * 32) + spritepatronen 2048 bytes (8 * 256) + sprite attr. 128 bytes (32 * 4) + Sprites: G2: Sprite Mode 1 + G3: Sprite Mode 2 + + Graphic 2 komt overeen met SCREEN 2, Graphic 3 komt overeen + met SCREEN 4. De enige twee verschillen tussen G2 en G3 + zijn: + + - G2 is wel MSX1 compatibel, G3 niet + - G2 heeft Sprite Mode 1, G3 heeft Sprite Mode 2 + + Aan het einde van het artikel zullen ook heel kort de beide + Sprite Modes en de verschillen worden behandeld. + + Om G2 resp. G3 te krijgen moet de VDP als volgt staan + ingesteld: + + M1 M2 M3 M4 M5 + G2 0 0 1 0 0 + G3 0 0 0 1 0 + + SCREEN 2 en 4 hebben drie pattern generators, deze pattern + generators werken net zo als de pattern generator van SCREEN + 1. Het scherm is verdeeld in drie gelijke delen van 8 regels + hoog: + + Regel 0 t/m 7: Pattern generator #1 + Regel 8 t/m 15: Pattern generator #2 + Regel 16 t/m 23: Pattern generator #3 + + Voor elke positie op het scherm (er zijn 768 posities) kan + dus een apart pattern worden gedefinieerd, omdat elke + pattern generator 256 patterns bevat. Een pattern uit + pattern generator #2 kan niet op regel 7 worden getoond! Op + deze manier wordt er een 256 bij 192 pixel scherm + gesimuleerd, terwijl er in feite toch met patterns + (karakters) wordt gewerkt. + + Het startadres van de pattern generator tables staan in R#4, + alleen de 4 hoogste bits (13 t/m 16) kunnen worden + opgegeven. Het startadres van de generator tables is dus + altijd een veelvoud van 8 kB. + + --------------------------------------------------------- + MSB 7 6 5 4 3 2 1 0 LSB + + R#4 0 0 A16 A15 A14 A13 1 1 Pattern Generator + --------------------------------------------------------- + + Hoewel bit 1 en 0 van R#4 in G2 en G3 altijd op "1" staan, + moet hiervoor toch 0 worden gelezen! In BASIC kan deze + waarde worden opgevraagd c.q. veranderd middeld BASE(12) in + SCREEN 2 of BASE(22) in SCREEN 4. + + Deze pattern generator tables zijn als volgt opgebouwd. Voor + elk patroon zijn acht bytes gereserveerd. Elke bit in die + byte stelt een pixel voor. Een 1 betekent dat dat pixel in + de voorgrondkleur wordt getoond, een 0 de achtergrondkleur. + + Op het adres dat in R#4 staat begint generator #1. Voor elk + pattern zijn 8 bytes gereserveerd. Er zijn 8 patronen, + genummerd van #0 t/m #255, dus de tabel is 2048 bytes lang. + Daarachter volgende generator #2 en #3 op dezelfde manier. + Een aantal voorbeelden (adres ten opzichte van waarde in + R#4): + + Adres: Bevat: + + 0 Regel 0 van pattern #0, generator #1 + 1 Regel 1 van pattern #0, generator #1 + 7 Regel 7 van pattern #0, generator #1 + 8 Regel 0 van pattern #1, generator #1 + 2047 Regel 7 van pattern #255, generator #1 + 2048 Regel 0 van pattern #0, generator #2 + 4095 Regel 7 van pattern #255, generator #2 + 5572 Regel 4 van pattern #184, generator #3 + 6143 Regel 7 van pattern #255, generator #3 + + Het beginadres van een bepaald pattern kan dus als volgt + worden berekend: + + adres = (generator-1)*2048 + pattern*8 + + + De kleurentabel werkt net zo, alleen wordt nu per regel van + een pattern aangegeven welke kleur de voorgrondkleur is en + welke kleur de achtergrondkleur. Hiervoor zijn dus ook 8 + bytes per pattern nodig. Er zijn ook drie kleurentabellen. + De kleurentabellen beginnen op het adres dat in R#3 en R#10 + wordt bepaald: + + -------------------------------------------------------- + MSB 7 6 5 4 3 2 1 0 LSB + + R#3 A13 1 1 1 1 1 1 1 Color table low + R#10 0 0 0 0 0 A16 A15 A14 Color table high + -------------------------------------------------------- + + Merk op dat alleen de vier hoogste bits kunnen worden + veranderd (bit 13 t/m 16). De bits 0 t/m 6 van R#3 zijn + altijd "1", toch moet daar voor worden gelezen! Ook deze + tabel begint dus altijd op een veelvoud van 8 kB. + + De kleurentabel is als volgt opgebouwd: + + MSB 7 6 5 4 3 2 1 0 LSB + + ---V--- ---A--- + 0 tabel 1 karakter 0 regel 0 + ---V--- ---A--- + 1 regel 1 + ---V--- ---A--- + 7 regel 7 + + ---V--- ---A--- + 6143 tabel 3 karakter 255 regel 7 + + Waarbij V voor de voorgrondkleur staat en A voor de achter- + grondkleur. Het beginadres van de kleuren van een pattern + kan als volgt worden gevonden: (tabel=1, 2 of 3) + + adres = (tabel-1)*2048 + pattern*8 + + De Pattern Name Table geeft aan welk karakter op elke + positie van het scherm wordt getoond. Het scherm is hierbij + verdeeld in drie blokken: upper, middle en lower. U raadt + het al: voor de posities in het upper gedeelte (regel 0 t/m + 7) wordt pattern generator #1 en color table #1 gebruikt, en + voor middle en lower #2 resp. #3. Op deze manier kan voor + elk van de 768 posities een ander pattern en andere kleuren + worden gekozen, waardoor een 256 bij 192 pixelscherm wordt + gesimuleerd. + + Het beginadres van de pattern name tabel staat in R#2. De + laagste 10 bits (bit 0 t/m 9) zijn altijd 0, de hoogste 7 + bits (10 t/m 16) staan in R#2. + + ---------------------------------------------------- + MSB 7 6 5 4 3 2 1 0 LSB + + R#2 0 A16 A15 A14 A13 A12 A11 A10 Pattern Name + ---------------------------------------------------- + + In BASIC is deze waarde op te vragen c.q. te veranderen + middels BASE(10) in SCREEN 2, en BASE(20) in SCREEN 4. + + De karakternummers staan in de Pattern Name Table van links + naar rechts, van boven naar onder. Dus: + + | 0 1 2 3 ... 31 + -----+----------------------------------------------- + 0 | 0 1 2 3 31 + 1 | 32 33 34 35 63 + ... | + 23 | 736 737 738 739 767 + + Het adres behorende bij de positie (X,Y) kan als volgt + worden berekend: + + + Y * 32 + X + + Nogmaals de tabel met de blokken: + + Naam: Regels: Pattrn: Color: + ------------------------------ + Upper 0-7 #1 #1 + Middle 8-15 #1 #1 + Lower 16-23 #1 #1 + ------------------------------ + + Let u hier goed op, patroon #13 is een heel ander patroon op + regel 7 dan op regel 8! + + De borderkleur wordt gedefinieerd met R#7, en wel door de + vier minst significante bits. + + ---------------------------------------------------- + MSB 7 6 5 4 3 2 1 0 LSB + + R#7 --ongeldig--- B3 B2 B1 B0 Border color + ---------------------------------------------------- + + + S C R E E N 4 V E E L G E B R U I K T + + Deze schermen zijn niet bitmapped (zoals de SCREENs 5 t/m + 8). Ze zijn daarom niet zo makkelijk te programmeren, om de + kleur van een bepaald pixel te veranderen moet er op drie + plaatsen in het VRAM iets worden veranderd, en bovendien + gaan er dan soms andere pixels in de buurt mee. Er kunnen + maar twee kleuren per acht horizontale pixels worden + gebruikt, dat komt de kwaliteit van de graphics ook niet ten + goede. De commando's van de VDP kunnen niet worden gebruikt + om te kopi�ren. + + Toch wordt SCREEN 4 behoorlijk vaak gebruikt bij MSX2 + software. Om maar eens een paar bekende titels te noemen: + Hydefos, Psycho World, Space Manbow (!!), Firehawk en + Superrunner. Misschien gelooft u het eerst niet (net als + ik), maar als u goed kijkt kunt u zien dat deze spellen + nergens meer dan twee kleuren per acht pixels gebruiken in + het speelscherm (vaak is het gedeelte met de score e.d. wel + in SCREEN 5, d.m.v. een screensplit). + + SCREEN 4 is op de sprites na gelijk aan SCREEN 2 op MSX1. + Waarom zijn bovengenoemde spellen dan niet voor MSX1 + gemaakt? De eerste reden noemde ik al: de sprites. In Sprite + Mode 2 mogen twee maal zoveel sprites op een horizontale + regel worden geplaatst, dus dat knippert een stuk minder. + Maar dat is niet de enige reden: door gebruik te maken van + de verticale hardwarescroll en het adjustregister van de + MSX2 kunnen op deze computer smooth scrolls in alle + richtingen worden gemaakt. Dat kan op MSX1 niet. + + In SCREEN 5 (veel meer een echt MSX2 scherm) kan dat veel + minder goed, omdat daar veel meer VRAM moet worden + verplaatst om te scrollen. En dat is nu precies het grote + voordeel van SCREEN 4 ten opzichte van SCREEN 5: SCREEN 4 + gebruikt minder VRAM en animaties nemen dus minder tijd in + beslag! + + + S P R I T E M O D E 1 E N 2 + + Nog even de verschillen tussen Sprite Mode 1 en Sprite Mode + 2. Eerst even een overzicht in welke schermen ze kunnen + worden gebruikt: + + Scherm: Sprite Mode: + ---------------------------- + T1 niet + T2 niet + MC 1 + G1 1 + G2 1 + G3 2 + G4 2 + G5 2 + G6 2 + G7 2 + ---------------------------- + + Kort overzicht van de verschillen: + + Sprite Mode 1: Sprite Mode 2: + ------------------------------------------------------------ + Kleuren 1 kleur per sprite 1 kleur per lijn + van een sprite + Aantal op ��n + horizontale 4 8 + lijn + + Sprite 32 pixels + naar links mogelijk mogelijk + verplaatsen per lijn + + Overlappende niet mogelijk mogelijk + sprites OR + (per lijn) + + Botsing detectie + uitzetten (per niet mogelijk mogelijk + lijn) + ------------------------------------------------------------ + + In deel zes van de VDP cursus wordt Sprite Mode 2 uitgebreid + besproken. Voor Sprite Mode 1 is er geen kleurentabel, + verder werken de tabellen hetzelfde. Behalve de attribuut- + tabel, daar wordt de byte die bij Sprite Mode 2 niet wordt + gebruikt, gebruikt voor de kleur van de sprite: + + Attributen per sprite: + + +0 Y coordinaat + +1 X coordinaat + +2 Patroon nummer + +3 Kleurcode (0-15) + + Indien bit 7 van de kleurcode wordt gezet, wordt de sprite + 32 pixels naar links verplaatst. Helaas weten veel + programmeurs niet wat hier het nut van is. Ik zal dat dus + maar eens uitleggen. + + + H E T N U T V A N E C + + Bit 7 van de kleurcode heet bij de beide Sprite Modes "EC". + Wat heeft het nu voor nut om een (gedeelte van een) sprite + 32 pixels naar links te verplaatsen? + + U kunt dit gebruiken om sprites ook aan de linkerkant van + het scherm pixel voor pixel te laten verdwijnen c.q. + verschijnen. Bij van links naar rechts bewegende sprites + zien we vaak dat de sprite aan de rechterkant netjes + verdwijnt, maar aan de linkerkant zomaar opeens helemaal op + het scherm staat. + + Dit komt omdat X-coordinaat 255 betekent dat alleen de meest + linkse pixels van de sprite nog uiterst rechts te zien zien, + en bij X=0 staat de sprite in zijn geheel strak tegen de + linkerkant van het scherm. + + U kunt dit voorkomen door op de juiste manier gebruik te + maken van het EC bit, dat dus ook op MSX1 al aanwezig was! + Stel u wilt een sprite van rechts naar links laten gaan, + terwijl de sprite aan beide kanten van het scherm pixel voor + pixel verschijnt c.q. verdwijnt. Dit gaat als volgt: + + 1) Zet EC op 0 + 2) Verander de X coordinaat van 255 naar 0 + 3) Zet EC op 1 en de X coordinaat gelijktijdig op 32 + 4) Verander de X coordinaat van 32 naar 0 + + Het is heel belangrijk dat stap 3 heel snel gebeurt, want + anders zal er een knippering in de animatie optreden. + + Ik hoop dat veel programmeurs dit nu ook gaan gebruiken, + want het is in sommige demo's en spellen echt geen gezicht! + + + T O T D E V O L G E N D E K E E R + + Hiermee sluit ik dit achtste deel af. De volgende keer + worden SCREEN 5 t/m 8 behandeld, oftewel Graphic 4 t/m 7. + Daarna kunnen we eindelijk beginnen met de praktijk- + voorbeelden, met zeer veel machinetaalroutines. + + Stefan Boer diff --git a/sunrise_special/5/VDP Cursus 9.md b/sunrise_special/5/VDP Cursus 9.md new file mode 100644 index 0000000..637643f --- /dev/null +++ b/sunrise_special/5/VDP Cursus 9.md @@ -0,0 +1,187 @@ + V D P C U R S U S 9 + + + Zoals beloofd deze keer de opslag van SCREEN 5 t/m 8 in het + VRAM, of liever gezegd de Graphic modes 4 t/m 7. Dit zijn + allen zgn. bitmap schermen, en de opslag in het VRAM gaat + dan ook bij allemaal volgens hetzelfde principe. + + + B I T M A P + + Bij het bitmap systeem wordt de kleur van ieder pixel + bepaald door een bepaald aantal bits. Deze bits worden + alleen voor dit pixel gebruikt, waardoor geen "color spill" + effecten optreden, zoals bij SCREEN 2 en 4 of de MSX2+ + schermen 10 t/m 12. + + Het aantal kleuren dat tegelijkertijd op het scherm kan + worden getoond is hierbij uiteraard afhankelijk van het + aantal bits dat per pixel beschikbaar is. Een overzichtje: + + SCREEN 5 G4 4 bits/pixel 16 kleuren + SCREEN 6 G5 2 bits/pixel 4 kleuren + SCREEN 7 G6 4 bits/pixel 16 kleuren + SCREEN 8 G7 8 bits/pixel 256 kleuren + + Deze bits worden zoveel mogelijk in een byte gepropt. Omdat + een byte zoals u ongetwijfeld weet uit 8 bits bestaat + betekent dat in G4 en G6 de kleuren van twee pixels in een + byte worden opgeslagen, bij G5 zijn dat er 4 en bij G7 + slechts 1. Hierbij is het zo dat de kleur van het meest + linkse pixel ook altijd in de meest linkse bits is + opgeslagen. Samengevat levert dit onderstaand schema op: + + MSB 7 6 5 4 3 2 1 0 LSB + G4 en G6 ------1------ ------2------ + G5 --1-- --2-- --3-- --4-- + G7 --------------1-------------- + + + V O L G O R D E + + We weten nu dus hoe de kleurinformatie over de bytes van het + VRAM verdeeld is, maar we weten nog niet in welke volgorde + die bytes staan, of waar we dus de kleurinformatie van een + bepaald pixel kunnen vinden. + + Deze informatie over de pixels wordt per lijn opgeslagen. De + eerste lijn van het scherm bestaat uit de pixels (0,0), + (1,0), (2,0), .... tot (255,0) op G4 en G7 resp. (511,0) op + G5 en G6. De kleuren staan van links naar rechts in het + VRAM. Als het beeldscherm uit slechts ��n lijn zou bestaan + zou dus de volgende formule gelden: + + = \ + + (Let op: er staat een "\" (integerdeling) en niet een "/" + (normale deling)!) De kleuren van de pixels (0,0) en (1,0) + staan op SCREEN 5 en 7 dus samen in byte 0, die er als volgt + uit ziet: + + MSB 7 6 5 4 3 2 1 0 LSB + ----(0,0)---- ----(1,0)---- + + Door een VPOKE 0,&HF1 wordt pixel (0,0) dus wit en pixel + (1,0) zwart. De kleur van het pixel (255,0) staat bij SCREEN + 8 in byte nummer 255, en neemt het hele byte in beslag. + + Natuurlijk bestaat het scherm niet uit slechts ��n lijn, + maar uit 212 lijnen (genummerd van 0 t/m 211). De informatie + van lijn 1 staat direct achter die van lijn 0, en daarachter + weer lijn 2, enz. We kunnen dus zeggen dat de informatie van + linksboven naar rechtsonder in het VRAM is opgeslagen. We + breiden de formule dus nog wat uit: + + = \ + + * + + Hierbij is de volgende tabel misschien handig: + + Aantal pixels per byte: Aantal bytes per lijn: + ------------------------------------------------------ + G4 2 128 + G5 4 128 + G6 2 256 + G7 1 256 + ------------------------------------------------------ + + + P A L L E T + + De modes 4 t/m 6 werken met een palet. Bij G4 en G6 bestaat + dit palet uit 16 kleuren, bij G5 uit 4. Het kleurnummer dat + in de databytes wordt opgeslagen correspondeert met het + paletnummer. + + Bij G7 (SCREEN 8) gaat het heel anders. Het kleurnummer is + hier als volgt opgebouwd: + + MSB 7 6 5 4 3 2 1 0 LSB + ----G---- ----R---- --B-- + + Hierbij staat G voor de groene intensiteit (0-7), R voor de + rode intensiteit (0-7) en B voor de blauwe intensiteit + (0-7). Er is hier dus geen sprake van een palet, de kleuren + staan vast. + + Het palet wordt bij SCREEN 5 t/m 7 door BASIC in het VRAM + gezet. Bij SCREEN 5 en 6 is dit &H7680, en bij SCREEN 7 + &HFA80. Het veranderen van deze waardes door VPOKE heeft pas + effect na een COLOR=RESTORE. In machinetaal wordt het palet + normaal gesproken gewoon veranderd door naar Port #2 te + schrijven (OUT poort &H9A). Hiervoor verwijs ik u naar deel + 1 van de VDP cursus. + + + G E H E U G E N G E B R U I K + + Zoals u weet hebben G4 en G5 4 pages, en G6 en G7 2. Deze + pages staan als volgt in het VRAM: + + 00000H page 0 G4/G5 page 0 G6/G7 + ------------ + 08000H page 1 G4/G5 + ------------ ------------ + 10000H page 2 G4/G5 page 1 G6/G7 + ------------ + 18000H page 3 G4/G5 ------------ + + Voor de VDP is een scherm 256 lijnen hoog, en er per page + dan ook 32 kB (G4/G5) respectievelijk 64 kB (G6/G7) in + beslag worden genomen. Van deze 256 lijnen worden er slechts + 212 (of 192) op het scherm getoond. Welke, dat wordt bepaald + door de waarde in R#23 (beter bekend als VDP(24)). + + Omdat de lijnen vanaf 212 normaal gesproken niet te zien + zijn, worden deze gebruikt om de spritedata in op te slaan. + Hiervoor verwijs ik u naar het deel van de VDP cursus dat + aan sprites was gewijd. SCREEN 5 t/m 8 hebben Sprite Mode 2. + + Bij het wegsaven van schermen met BSAVE kunt u de volgende + eindadressen gebruiken: + + SCREEN: met palet: zonder palet: + --------------------------------------------- + 5 &H769F 27135 + 6 &H7687 27135 + 7 &HFA9F 54271 + 8 nvt 54271 + --------------------------------------------- + + + S C R E E N S E L E C T E R E N + + Tot slot nog even de juiste bits om de schermen te + selecteren. U vindt deze bits in R#0 en R#1, waarvan ik dus + eerst maar even de indeling geef: + + MSB 7 6 5 4 3 2 1 0 LSB + R#0 0 DG IE2 IE1 M5 M4 M3 0 Mode Reg #0 + R#1 0 BL IE0 M1 M2 0 SI MAG Mode Reg #1 + + Het gaat om de bits M1 t/m M5. Bij de in dit artikel + besproken grafische schermen horen de volgende waardes van + M1 t/m M5: + + M1 M2 M3 M4 M5 + ------------------------------------------ + G4 0 0 1 1 0 + G5 0 0 0 0 1 + G6 0 0 1 0 1 + G7 0 0 1 1 1 + ----------------------------------------- + + + T O T S L O T + + Hiermee is een eind gekomen aan het zeer lange overzicht van + alle theorie betreffende de Video Display Processor in uw + MSX computer. Dit betekent niet dat de cursus nu stopt, in + tegendeel. Vanaf het volgende deel zullen we toepassingen + gaan behandelen. Het geleerde zal dan eindelijk in + machinetaal worden toegepast. + + Tot de volgende keer! + + Stefan Boer diff --git a/sunrise_special/5/Werken met ASCII C deel 3.md b/sunrise_special/5/Werken met ASCII C deel 3.md new file mode 100644 index 0000000..9b92b23 --- /dev/null +++ b/sunrise_special/5/Werken met ASCII C deel 3.md @@ -0,0 +1,293 @@ + H E T W E R K E N M E T A S C I I C + + D E E L 3 + + + H E T G E N E R E R E N V A N S N E L L E + + C O D E M E T A S C I I M S X C + + + Zoals ook al in deel 1 van deze serie staat vermeld, + genereert de code optimizer van ASCII MSX C vrij snelle + code. Er kan echter met deze compiler in verschillende modi + gewerkt worden die allemaal hun eigen invloed hebben op de + snelheid van de gegenereerde code. + + In dit deel van de cursur zullen achtereenvolgens de + volgende onderwerpen worden besproken: + + 1) De compiler directives 'nonrec' en 'recursive' + 2) De compiler directives 'noregalo' en 'regalo' + 3) Algemene wenken voor het maken van snelle code + 4) De werking van XESCO + 5) Het gebruik van XESCO + 6) Aanwijzingen m.b.t. de source van XESCO + + [Nvdr. Omdat XelaSoft's Code Optimizer een beetje lang is, + heb ik de afkorting XESCO verzonnen.] + + + 1 ) D E C O M P I L E R D I R E C T I V E S + + N O N R E C E N R E C U R S I V E + + Normaal gaat de compiler ervan uit dat alle functies + recursief zijn. Daarom wordt de code zo aangemaakt dat een + functie alle locale variabelen op de stack bijhoudt. Dit is + echter niet bevordelijk voor de snelheid. Aangezien ook + ASCII dit heeft ingezien, hebben ze hier een oplossing voor + verzonnen: Als je weet dat een bepaalde functie niet + recursief is dan kun je dit aan de compiler vertellen met de + compiler directive 'nonrec'. + + V O O R B E E L D + + Stel je hebt de volgende functie die de som van een lijst + getallen berekent + + int sum(lijst, aantal) + int *lijst; + int aantal; + { + int sum; + + while (aantal--) + sum += *(lijst++); + return sum; + } + + Deze functie is niet recursief (ze roept zichzelf namelijk + nergens aan, ook niet via een omweg). + + Om dit aan de C compiler door te geven dient de header van + de functie vervangen te worden door: + + nonrec int sum(lijst, aantal) + + + Als je wilt hebben dat de compiler vanaf een bepaald punt in + de source voor alle functies niet recursieve code genereert, + dan kan dit met een compiler directive, namelijk: + + #pragma nonrec /* alle functies vanaf + hier zijn niet recursief */ + + En dit kan weer worden uitgezet met: + + #pragma recursive /* alle functies vanaf + hier zijn recursief */ + + + 2 ) D E C O M P I L E R D I R E C T I V E S + + N O R E G A L O E N R E G A L O + + De compiler van ASCII doet normaal aan + register-optimalisatie, dit houdt in dat locale variabelen + zoveel mogelijk in de registers worden bijgehouden. Pas als + dit niet kan (er zijn bijv. teveel variabelen tegelijk in + gebruik), dan worden sommige variabelen in het geheugen + bijgehouden. Dit laatste kan dus op twee manieren gebeuren, + namelijk op de stapel (bij recursieve procedures) of via + directe adressering in het 'normale' geheugen (bij niet + recursieve procedures). + + Soms kan de register-optimalisatie misgaan, in dit geval kan + de register-optimalisatie worden uitgezet met: + + #pragma noregalo /* vanaf hier wordt geen register- + optimalisatie gebruikt */ + + Het weer aanzetten kan vervolgens met: + + #pragma regalo /* vanaf hier wordt wel register- + optimalisatie gebruikt */ + + Een voorbeeld waarin de register-optimalisatie misgaat (uit + de C handleiding). + + int n; + int *p; + + p = &n; + n = 10; + *p = 100; + printf("%d", n); + + In dit geval zijn er slechts 2 variabelen, namelijk n en p. + Deze kunnen dus in registers worden bijgehouden. De compiler + zal de waarde 10 dan ook in het register zetten waarin n + wordt bijgehouden en dit register vervolgens doorgeven bij + de printf instructie. Het feit dat de echte waarde van n dan + via de pointer p is veranderd ziet de compiler niet. Dit zou + wel goed gaan als de code er als volgt uit had gezien: + + int n; + int *p; + + n = 10; + p = &n; /* nu zijn n = 10 en p = &n verwisseld */ + *p = 100; + printf("%d",n); + + De compiler zal nu namelijk de waarde van n in het geheugen + opslaan voordat in de pointer p het adres van de variabele n + wordt gestopt, en bij de printf zal de waarde van deze n + weer worden opgehaald. + + Bij de register-optimalisatie kijkt de compiler naar het + totale variabelen gebruik binnen een functie. In het + algemeen is het zo dat als er binnen een lus maar weinig + variabelen worden gebruikt, dat dan de variabelen binnen die + lus in registers worden bijgehouden. Buiten de lus kan de + register-optimalisatie weer anders zijn. + + Verder is het zo dat de compiler bij korte functies vaak + beter herkent wat in registers kan dan bij grote, complexe + functies. Het is daarom verstandig om een grote functie + zoveel mogelijk op te splitsen in kleinere functies die dan + worden aangeroepen vanuit die grote functie (vanuit het + standpunt van gestructureerd programmeren bekeken is dit + toch al aan te bevelen!). + + + 3 ) A L G E M E N E W E N K E N V O O R + + H E T M A K E N V A N S N E L L E C O D E + + Kort samengevat is de algemene werkwijze voor het maken van + snelle code als volgt: + + - Geef aan welke functies niet recursief zijn zodat de + compiler bij deze functies de variabelen niet op de stack + hoeft bij te houden. + + - Laat de register-optimalisatie zoveel mogelijk aanstaan. + Mocht de register-optimalisatie in een zeldzaam geval + misgaan, kijk dan of je de code kunt herschrijven. Gebruik + de '#pragma noregalo' directive pas als het niet anders + kan. + + - Maak liever veel kleine functies dan een paar grote. Let + er bij de opsplitsing in kleine functies wel op, dat je + geen extra complexiteit introduceert doordat je een + ingewikkeld algoritme te ver probeert op te splitsen! + + + 4 ) D E W E R K I N G V A N X E S C O + + Als bovenstaande werkwijze wordt gevolgd, kan er behoorlijk + snelle code worden verkregen. Het kan echter nog sneller. + Zoals namelijk ook al in deel 1 stond, maakt de code + generator alleen gebruik van instructies die de Intel 8080 + kent. Hierdoor worden sommige dingen een beetje dom + aangepakt (vanuit Z80 standpunt bekeken), een voorbeeld + hiervan is het volgende stuk code: + + push hl + ld hl,(variable) + ld c,l + ld b,h + pop hl + + Dit kan op de Z80 natuurlijk een stuk eenvoudiger, op de Z80 + kan het namelijk als volgt: + + ld bc,(variable) + + Om dit soort stukken Intel 8080 code te vervangen door + equivalente Z80 instructies heb ik een code optimizer + geschreven. Deze optimizer kan tussen de code generatie en + de assemblatie in komen. De C batch file kan er dan + bijvoorbeeld als volgt komen uit te zien: + + (Staat op disk als C.BAT.) + + cf %1 + cg -k %1 + optimize %1.mac %1.opt + del %1.mac + ren %1.opt %1.mac + m80 =%1 + del %1.mac + l80 ck,%1,clib/s,crun/s,cend,%1/n/e:xmain + + XESCO kan de meeste 8080 LD instructie-groepen vervangen + door de juiste Z80 LD instructie. Verder worden de shift + instructies iets effici�nter opgelost. Normaal maakt de + compiler voor iedere shift instructie een CALL naar een + systeemroutine (uit CRUN.REL). De routines die hier staan + zijn dan ook nog op zo'n algemene manier geschreven dat + zelfs een >>0 of <<0 goed wordt uitgevoerd. Dit introduceert + echter extra overhead (namelijk de CALL en de RET instructie + en de controle op een 0-count). Daarom vervangt de code + optimizer een call naar een shift instructie door een stukje + code dat deze shift instructie uitvoert. Hierbij kan de + optimizer 2 verschillende stukken code aanmaken: + + - Code die wel controleert op een 0-count (het standaard + geval) + + - Code die niet controleert op een 0-count. Om dit 2de geval + te krijgen dien je de optie /z op te geven. Doe dit alleen + als je zeker weet dat er geen shift over een afstand van 0 + bits kan voorkomen! + + Verder is het zo dat de code optimizer ook nog controleert + of je een shift over een constante afstand doet. Als je + namelijk over een afstand van 1 of van 2 schuift (dus >>1, + >>2, <<1 of <<2), dan wordt er geen lus gemaakt om de shift + instructie uit te voeren, maar er worden een paar register + shift instructies achter elkaar gezet. + + Behalve deze Z80-optimalisaties kent XESCO ook nog twee + R800-optimalisaties. Deze kunnen worden geactiveerd met de + optie /R. Als deze optie is opgegeven worden namelijk alle + calls naar de multiply routines vervangen door R800 multiply + instructies. In dit geval is de code uiteraard wel alleen + nog maar geschikt voor de MSX turbo R. + + + 5 ) H E T G E B R U I K V A N X E S C O + + Het gebruik van de code optimizer is als volgt: + OPTIMIZE sourcefile destinationfile [optionele parameters] + + Hiermee wordt het bestand 'sourcefile' ingelezen, en de + geoptimaliseerde code wordt weggezet in het bestand + 'destinationfile'. + + De optionele parameters zijn: + /Z: controleer niet op een 0-count bij de shift instructies + /R: gebruik de multiply instructie op de R800 + + Op deze disk staan 2 versies van de code optimizer, + namelijk: + + OPTD1.COM: de optimizer gecompileerd met MSX C 1.1, voor + onder MSX-DOS 1. + OPTD2.COM: de optimizer gecompileerd met MSX C 1.2, voor + onder MSX-DOS 2 + + + 6 ) A A N W I J Z I N G E N M . B . T . D E + + S O U R C E V A N X E S C O + + Behalve de gecompileerde versies, staat ook de source van de + optimizer op de disk, deze source bestaat uit 2 bestanden: + OPTIMIZE.C: de source van de optimizer + PCMSX.H : een headerfile om de optimizer zowel op de PC + als op de MSX te kunnen compileren. + + Deze source is public domain, ze dient ter studie ende + vermaak en mag NIET gewijzigd worden verspreid (veranderen + voor eigen gebruik mag, maar verspreid de veranderde source + en de object code die erbij hoort niet!). Laat het me weten + als je nog interessante idee�n hebt voor toekomstige versies + van XESCO zodat ze verwerkt kunnen worden. Ik ben bereikbaar + op onderstaand adres of via email op het adres: + wulms@stpc.leidenuniv.nl + + Alex Wulms diff --git a/sunrise_special/5/Z80dis.md b/sunrise_special/5/Z80dis.md new file mode 100644 index 0000000..46c8857 --- /dev/null +++ b/sunrise_special/5/Z80dis.md @@ -0,0 +1,367 @@ + Z 8 0 D I S + + + Z80DIS is een programma dat van een willekeurige + machinetaalfile een assemblerlisting maakt. Het programma is + geschreven door Kenneth Gielow voor CP/M, en draait (dus) + ook op MSX. + + Het is een aardige klus om uit een brok ML weer een + fatsoenlijke assemblerlisting, inclusief labels enzovoort, + te fabriceren. Maar Z80DIS doet het heel aardig. Volgens de + maker heeft het programma dan ook kunstmatige intelligentie + aan boord. Wat hij hier nou precies onder verstaat weet ik + niet, maar het werkt wel in ieder geval... + + Z80DIS moet altijd in de default-drive aanwezig blijven, + omdat het programma met overlay-files werkt die tussentijds + worden ingeladen. + + Na de nodige meldingen begint het programma met: + + Input filename: ________.COM + Output filename: none.MAC + Listing filename: ________.PRN + + De invoer-routine is misschien even wennen. Laat je echter + niet misleiden: er kan gewoon een drivenaam en een andere + extensie ingegeven worden. Als er alleen een filenaam + ingetypt wordt, zal Z80DIS hier dus zelf filenaam.COM van + maken. + + Let op: al staat de filenaam al voorgeprint, typ niet alleen + de drivenaam of een gedeelte van de naam in. Als je iets + wilt wijzigen, moet je meteen alles intypen (behalve de + extensie, als je die niet wilt wijzigen). + + Descriptive title: ______________________________________ + (Dit wordt bovenaan de ASM-listing gezet.) + + File load address: + Dis start address: + Dis stop address: + + Als er een stuk code middenin een file moet worden + gedissassembleerd, moet er eerst uitgerekend worden waar de + file eigenlijk zou moeten beginnen, om het interessante stuk + op het goede geheugenadres in te laden. + + Bijvoorbeeld: BLOAD-files beginnen altijd met een header van + 7 bytes. Als er een BLOAD-file van &H8000 tot &H87FF moet + worden gedisassembleerd, vul dan in: file load address: 7FF9 + (= &H8000 - 7), dis start address 8000, dis stop addres + 87FF. + + + Do you want to run a full output (as opposed to XREF only)? + + Als hier "N" ingegeven wordt, wordt in de .PRN-uitvoerfile + alleen de structuur en de gebruikte labels gegeven. Wordt + hier "Y" ingegeven, dan wordt ook de source-listing gegeven. + Zie ook verderop in de tekst. + + On which disk do you want the scratch file to reside? (A-G) + + De disk voor opslag van tijdelijke files. Natuurlijk kan + hier het beste een RAMdisk voor genomen worden. + Let op: Z80DIS kan drive H: niet aan. Geef dus onder DOS 2 + eerst bv. een ASSIGN G: H: + + Nvdr. Als je op RETURN drukt neemt Z80DIS de default drive. + Als je dus op de RAMdisk werkt, moet je gewoon op RETURN + drukken. + + Do you want to process all Z80 codes + (as opposed to 8080 equivalents only?) + + Ik neem aan dat iedereen hier gewoon voor "Y" kiest... + + + C O N T R O L B R E A K D E F I N I T I O N S + + Na deze vragen gaan we naar het volgende deel, waar de + "control break definitions" kunnen worden gemaakt. + + Hiermee kan aangegeven worden hoe de ML is opgedeeld in: + I: Instructies + B: Bytes (DEFB) + W: Words (DEFW) + A: ASCII karakters (DEFM) + S: Losse ruimte, die niet wordt gedisassembleerd. (DEFS) + T: "Table of addr". + Een "Table of addr" is een stuk met allemaal DEFW (LABEL) + instrukties. Ik weet eerlijk gezegd niet wat hiermee gedaan + kan worden. + + Als een van deze letters ingetypt wordt, wordt er gevraagd + om een beginadres waar dit type code begint. Op deze manier + kan van heel het stuk code de vorm worden bepaald, waarin + het wordt gedisassembleerd. + + Verdere geldige commando's in dit gedeelte zijn: + + H: Help beknopt overzicht commando's + C: Clear break table begin opnieuw met een lege + indeling + L: List break table laat de huidige "control break + definitions" zien + P: Print break table lijst naar printer + (Dit werkt helaas niet. Als de + printer off-line is wordt er + gewacht maar als hij on-line + gezet wordt, wordt er niets + afgedrukt. + K: Kill break entry point voor als er een verkeerd adres + is ingevoerd. + Als er een niet bestaande entry + point wordt verwijderd, wordt + geen melding gegeven, dus let + zelf goed op. + FL: load break table + FS: Save break table De indeling kan ook naar disk + worden weggeschreven. (Standaard + extensie: BRK.) Dit is heel + handig: als er later ontdekt + wordt dat er een foutje is + gemaakt, hoef je niet heel de + indeling opnieuw in te typen. + En het belangrijkste: + + *: Auto-assignment + + Hier komt de kunstmatige intelligentie om de hoek kijken. + Het programma is namelijk in staat het hele stuk code af te + zoeken en zelf de "control break table" in te delen. + + Alle dingen die Z80DIS niet thuis kan brengen ('anomalies') + worden gemeld. (Er wordt ook de mogelijkheid geboden deze + meldingen uit te printen, wat helaas weer niet lukt.) Hierna + komt men weer in het gedeelte waar de "break table" zelf + ingedeeld kan worden. + + Het is vaak het beste om "Auto-assignment" meerdere keren + achter alkaar uit te voeren, om zo het beste resultaat te + krijgen. + + Bij grote stukken code kan het voorkomen dat Z80DIS afbreekt + en (slordig) zonder enige melding meteen naar DOS wordt + teruggekeerd. In dit geval is het geheugen, dat Z80DIS + gebruikt voor de opslag van labels en dergelijke, vol. Het + gebruik van DOS 1 of 2 heeft geen invloed op de grootte van + dit geheugen. Het enige wat gedaan kan worden is een kleiner + stuk code disassembleren - of zelf de "break table" indelen. + + De grootte van het stuk dat kan worden gedisassembleerd + verschilt per brok code. Omdat er een tellertje meeloopt, is + het meestal na te gaan hoe groot het stuk code genomen moet + worden zodat het geheugen nog net niet vol is. + + De resultaten van "Auto-assignment" zijn behoorlijk goed, + maar er zitten een paar onvolkomenheden in (zoals te + verwachten was). Dingen die ik tot nu toe ontdekt heb: + + - Als na een CALL een LD HL,nn of LD IX/IY,nn instruktie + staat, maakt hij van deze ene instruktie meestal ASCII + tekens. + + - Z80DIS geeft ook labels aan die midden in een instruktie + voorkomen. (met bv. LABEL: EQU $-1) Dit is natuurlijk heel + mooi maar meestal betekent dit dat er een fout in die + instruktie zit. + + Met andere woorden: wie na het disassembleren de listing op + fouten na wil kijken, kan het best beginnen met in een + tekstverwerker alle "$" tekens na te zoeken. Ook het + nakijken van alle DEFM's is aan te raden, zoals uit de + eerste opmerking volgt. + + - Het programma is niet opgewassen tegen blokken vol met + bytes &HC9. Het ziet dit niet als bytes maar als allemaal + losse RET instrukties, met als gevolg dat het geheugen voor + labels binnen de kortste keren vol is. + + Als deze dingen (eerste en derde opmerking) handmatig in de + break table worden veranderd, kan er geen auto-assignment + meer gedaan worden, want Z80DIS herstelt dan zelf de 'foute' + situatie weer. + + + Het laatste commando is: + Q: Quit + + Het control break-gedeelte wordt verlaten en er wordt met + het echte disassembleerwerk begonnen. Als de .BRK file nog + niet is weggeschreven, wordt gevraagd of dit alsnog gedaan + moet worden. + + Ook tijdens het disassembleren kan het gebeuren dat het + geheugen vol is en er zonder melding naar DOS gesprongen + wordt. Kijk uit: het kan dus zo zijn dat er dan een niet + complete assembleerlisting op disk staat. + + Er is weer aan een tellertje te zien of het einde inderdaad + gehaald wordt zonder geheugenproblemen. + + + D E I N D E L I N G V A N + + D E . P R N E N . M A C F I L E S + + De gemaakte .PRN file bevat de volgende dingen: + + - titel en een paar andere meldingen + + - de "control break table" + + - een lijst van alle labels, met vermelding van alle + adressen waar die labels gebruikt worden en de funktie die + ze op dat adres hebben. (zie verderop) + + - een lijst van alle subroutines, met weer alle + aanroepadressen/funkties vermeld. Ook is er een een regel + opengehouden voor de beschrijving van de subroutine. + + - de source-listing + Aan de linkerkant van de listing is een kolom voor, bij + elke instruktie, de geheugenadressen en de inhoud van de + adressen die de instruktie in beslag neemt. Bij elke + subroutine zijn regels gereserveerd voor commentaar + (funktie, inputs, outputs). + + De .MAC file is een source-listing die meteen door een + geschikte assembler heen gehaald kan worden. Dit is + hetzelfde als het laatste deel van de .PRN file maar zonder + kolommen met getallen aan de linkerkant. + + De source-listings zijn niet direkt geschikt voor GEN80/M80. + Dit komt door de naamgeving van de labels. In de file + Z80DIS.PMA zit echter wel het programma ZSM.COM hiermee zijn + de sources wel te assembleren. + + De hexadecimale getallen zijn van de vorm xxxxH. + + Mensen die de listings in WBASS willen gebruiken, moeten: + - in een tekstverwerker de TABS in spaties omzetten; + - EX AF,AF' in EX AF,AF veranderen + - 'string' in "string" veranderen (bijv. bij DEFB) + - Zelf iets verzinnen als er bv. LABEL: EQU $-1 voorkomt. + + + L A B E L S E N H U N F U N K T I E S + + Een label bestaat uit 6 tekens. Aan een paar labels wordt al + een standaard naam (van een CP/M routine) toegekend. Voor de + overige labels hangt het eerste teken af van de funktie van + het betreffende geheugenadres: + + C als er ergens een CALL/RST naar het label gemaakt wordt + J " " JP/JR " " + D als het betreffende adres voor data-opslag gebruikt wordt + I (immediate) als het label gewoon een getal is (dat alleen + in een registerpaar geladen wordt. Alle 16 bits getallen + worden namelijk labels gemaakt.) + . als het betreffende label niet wordt gebruikt in de + listing, bijvoorbeeld als het een begin is van een + routine die nergens wordt aangeroepen. + + Als C en J allebei voor hetzelfde label voorkomen, wordt + C genomen. Dit is ook zo bij C en I. + X voor alle overige combinaties van funkties + + Dat van alle 16 bits getallen labels worden gemaakt is soms + handig, soms niet. Als er ergens een CALL naar een routine + gemaakt wordt en puur toevallig wordt precies dezelfde + waarde ergens in HL geladen, wordt aan de CALL .... en de LD + HL,.... hetzelfde label toegekend. + + Het tweede teken is een # als er in de ASM-listing precies 1 + keer naar het label verwezen wordt en een . (punt) in alle + andere gevallen. Het derde t/m zesde teken bestaat uit het + betreffende adres (hexadecimaal). + + + Bij de vermelding van adressen, met de funktie die het label + op elk adres heeft, worden voor de funkties de volgende + afkortingen gebruikt: + + C : CALL naar label + Cr: RST naar label + J : JP naar label + Jr: JR naar label + Sb: byte schrijven + Sw: word schrijven + Lb: byte lezen + Lw: word lezen + Iw: het label is gewoon een getal + + + I N D E P R A K T I J K . . . + + ... is het een heel mooi programma maar heeft het toch zijn + beperkingen qua grootte van het te disassembleren stuk code. + Ook kan het soms behoorlijk lang duren. + + Ik heb een aantal dingen uitgeprobeerd en ben op ongeveer de + volgende resultaten gekomen (hoewel ik het niet precies + ge-timed heb): + + Op een turbo R met ramdisk doet Z80DIS bijna 2 minuten over + een "auto assignment" ronde van 12 kB code. (Dit is + overigens ongeveer de grootte waar je er nog net zeker van + bent dat het geheugen niet vol raakt.) Om de code optimaal + te krijgen moet er 4 a 5 keer auto assignment uitgevoerd + worden. Daarna duurt het disassembleren zo'n 2 1/2 minuut. + (Hier is 8 tot 9 kB het maximum.) + + In Z80 mode gaat het ongeveer 5 a 6 keer zo langzaam. Hier + kom je dus uit op meer dan een uur voordat de ASM-listing + klaar is. (In het ideale geval dat Z80DIS dus niet + "afbrak"... Anders ben je nog een tijd aan het zoeken naar + de maximaal toegestane grootte van het stuk ML.) Mensen die + daarna de listing gaan nakijken op fouten, de control break + instellingen veranderen en weer gaan disassembleren en + nakijken, mogen zo'n 2 uur uittrekken... + + Die 12 kB code levert een .PRN file van bijna 200 kB op en + een .MAC file van 80 kB. Mensen zonder veel geheugen hoeven + dus geen grote .PRN files aan te maken. + + Natuurlijk zal een klein stuk ML weinig problemen opleveren. + Hier hoeft ook minder keer auto assignment te worden gedaan. + Maar wees alvast gewaarschuwd... + + Toch is en blijft Z80DIS een prachtig hulpmiddel voor + iedereen die wel eens een sourcelisting van een stuk ML + nodig heeft of door wil spitten. En welke MSX'er met een + beetje ML-kennis heeft dat nou nooit? + + + T I P S + + Mensen die TED gebruiken, kunnen het beste een aparte + TED-file maken met de beste instellingen voor de + assemblerlistings: + + - TAB-instellingen (F2/T) op AAN, AAN, UIT om de file zo + klein mogelijk te houden. (Door de laatste UIT te zetten + duurt het laden wel iets langer. Maar Z80DIS kent niet + overal optimaal TABS toe, dus het is het beste om hem toch + uit te laten staan.) + - TABs op kolommen 9, 17, 25, ... 8n+1 (net als onder + BASIC/DOS) + - Edit mode (F3/S/E) AAN, om geen spaties aan het eind van + regels te krijgen. + - "Bewaar instellingen bij elke tekst" (F2/B/E) UIT, om geen + overbodige .TED files te krijgen. De instellingen zijn + toch voor elke file hetzelfde. + + Misschien handig om te weten: De .BRK file is een gewone + tekstfile die in een tekstverwerker ingeladen/veranderd kan + worden. Alleen hier staan de control breaks in veel + beknoptere vorm in als Z80DIS ze weergeeft. + + Ook handig om te weten: Als Z80DIS tijdens Auto Assignment + naar DOS teruggaat, staat in de tekstfile Z80DIS2.$$$ de + lijst met anomalies. + + Roderik Muit diff --git a/sunrise_special/6/Bepalen van nulpunten.md b/sunrise_special/6/Bepalen van nulpunten.md new file mode 100644 index 0000000..fdb2c3b --- /dev/null +++ b/sunrise_special/6/Bepalen van nulpunten.md @@ -0,0 +1,209 @@ + B E P A L E N V A N N U L P U N T E N + + + In de serie numerieke wiskunde op de Special is deze keer + het bepalen van een nulpunt van een niet-lineaire functie + aan de beurt (de methodes kunnen uiteraard ook voor lineaire + functies worden gebruikt, maar dat is onzinnig omdat de + oplossing daarvan gewoon kan worden uitgerekend). + + f(x) is een functie van R naar R en we zijn op zoek naar een + x waarvoor geldt f(x) = 0. Er kunnen uiteraard meerdere + nulpunten zijn, de hier besproken algoritmes geven echter + slechts ��n nulpunt. Indien je alle nulpunten wilt vinden + moet het algoritme dus meerdere keren worden aangeroepen met + een ander startinterval. We gaan er van uit dat f een + continue functie is. + + + B I S E C T I E + + Het meest voor de hand liggende algoritme om dit probleem + aan te pakken is bisectie. Deze methode is gebaseerd op de + tussenwaardestelling: + + Zij J een interval, en f: J --> R een continue functie. Neem + x1 en y1 uit J, zo dat x1 < y1, zij c een waarde tussen + f(x1) en f(y1). Dan bestaat er een t zo dat x1 <= t <= y1 en + f(t)=c. + + Het bewijs laat ik hier achterwege, voor het bewijs wordt + overigens een techniek gebruikt die sterk lijkt op bisectie! + Het komt erop neer dat als bijvoorbeeld f(1)=3 en f(2)=5, en + f(x) is continu, dat f(x) dan ergens tussen 1 en 2 de waarde + 4 aan moet nemen. + + Je begint met een gesloten interval [a,b] waarvoor geldt + f(a)f(b) < 0. Volgens de tussenwaardestelling ligt er dan + minstens ��n nulpunt in [a,b]. De tekens van f(a) en f(b) + zijn immers verschillend als f(a)f(b) < 0. + + Vervolgens bereken je c als het midden van het interval, dus + c := (a+b)/2. Nu zijn er drie gevallen te onderscheiden: + + f(a)f(c) < 0: het nulpunt ligt in [a,c] + f(a)f(c) > 0: het nulpunt ligt in [c,b] + f(a)f(c) = 0: c is het nulpunt + + In de eerste twee gevallen neem je [a,c] respectievelijk als + het nieuwe interval en ga je weer verder, anders ben je + klaar. Aangezien de computer niet met oneinige precisie + werkt kan het optreden dat dat nooit voorkomt, daarom is het + nodig om een stopcriterium in te bouwen, we be�indigen het + algoritme ook als de lengte van het interval kleiner is dan + een bepaalde tolerantie (een heel klein getal, bijvoorbeeld + 0.000000000001). + + Ik heb dit algoritme geprogrammeerd in het onderstaande + BASIC programma dat ook op de disk te vinden is. Probeer het + eens uit met als startinterval [0.5,1]. Je kunt natuurlijk + ook een andere functie proberen. Het programma zal je + waarschuwen indien je een verkeerd startinterval kiest. + + + 100 ' BISECTIE.BAS + 110 ' Zoek de oplossing van het probleem f(x) = 0 + 120 ' door gebruik te maken van de bisectiemethode + 130 ' Door Stefan Boer + 140 ' Sunrise Special #6 + 150 ' (c) Stichting Sunrise 1994 + 160 ' + 170 ' Zet hier de functie + 180 ' + 190 DEFFN F(X)=(X+1)*(X+1)*EXP(X*X-2)-1 + 200 ' + 210 CLS:PRINT"Bisectie":PRINT + 220 INPUT"a = ";A + 230 INPUT"b = ";B + 240 IF FNF(A)*FNF(B) >= 0 THEN PRINT"Kies een ander + interval!":GOTO 220 + 250 PRINT"a";TAB(20);"b";TAB(40);"c";TAB(60);"f(c)" + 260 C=(A+B)/2 + 270 PRINT A;TAB(20);B;TAB(40);C;TAB(60);FNF(C) + 280 IF ABS(A-B)<1E-12 THEN 310 + 290 Y=FNF(A)*FNF(C) + 300 IF Y<0 THEN B=C:GOTO 260 ELSE IF Y>0 THEN A=C:GOTO 260 + 310 PRINT:PRINT"Nulpunt:";C + + + F A L S E P O S I T I O N + + Bij bisectie maak je alleen gebruik van het teken van f(a) + en f(b), niet van de waarde. Je gebruikt dus niet alle + informatie. Door dit wel te doen kun je in minder stappen + het nulpunt bepalen. Je neemt als c het snijpunt met de x-as + van de lijn die de punten (a,f(a)) en (b,f(b)) met elkaar + verbindt. Dit algoritme heet false position. + + Ik zal nu de afleiding van de formule voor dit algoritme + laten zien. De parametrische voorstelling van de rechte lijn + is: + + y - f(a) = m (x - a) + + waarbij m de richtingsco�ffici�nt van de lijn is: + + f(b) - f(a) + m = ----------- + b - a + + Het invullen hiervan in de bovenste vergelijking en y = 0 + (we willen immers het snijpunt met de x-as hebben) levert + op: + + a f(b) - b f(a) + c = ---------------- + f(b) - f(a) + + Vervolgens doe je hetzelfde als bij bisectie. Het + stopcriterium van bisectie is hier echter ongeschikt, omdat + bij sommige functies de lengte van het interval niet kleiner + kan worden dan een bepaalde waarde (teken maar eens een + plaatje van de functie (1/x) - 1 met het interval [0,5]). We + kiezen daarom het stopcriterium |c(i+1) - c(i)| < epsilon + waarbij c(i+1) de nieuwe c is en c(i) de oude c. Epsilon is + de tolerantie. + + Ik heb ook dit algoritme in BASIC geprogrammeerd. Als je het + met dezelfde functie en hetzelfde startinterval probeert zul + je zien dat het in veel minder stappen convergeert dan + bisectie, het gaat echter niet veel sneller omdat het + berekenen van c meer tijd kost. Bij de meeste functies zal + false position minder stappen nodig hebben dan bisectie. + + + 100 ' FALSEPOS.BAS + 110 ' Zoek de oplossing van het probleem f(x) = 0 + 120 ' door gebruik te maken van de false position methode + 130 ' Door Stefan Boer + 140 ' Sunrise Special #6 + 150 ' (c) Stichting Sunrise 1994 + 160 ' + 170 ' Zet hier de functie + 180 ' + 190 DEFFN F(X)=X*X+LOG(X) + 200 ' + 210 CLS:PRINT"False position":PRINT + 220 INPUT"a = ";A + 230 INPUT"b = ";B + 240 PRINT:PRINT"a";TAB(20);"b";TAB(40);"c";TAB(60);"f(c)" + 250 CC=C:C=(A*FNF(B)-B*FNF(A))/(FNF(B)-FNF(A)) + 260 PRINT A;TAB(20);B;TAB(40);C;TAB(60);FNF(C) + 270 IF ABS(CC-C)<1E-12 THEN 300 + 280 Y=FNF(C)*FNF(A) + 290 IF Y<0 THEN B=C:GOTO 250 ELSE A=C:GOTO 250 + 300 PRINT:PRINT"Nulpunt:";C + + + Z O N D E R I N T E R V A L + + Dit waren twee algoritmes die werken met een interval. Er + zijn drie algoritmes die met ��n punt werken: vast punt, + Newton-Raphson en secant. De eerste twee zijn minder + geschikt om in BASIC te programmeren en de secantmethode + voegt niets nieuws toe. Ik zal dat hieronder per algoritme + uitleggen. + + + V A S T P U N T + + Bij het vast punt algoritme herschrijf je het probleem f(x) + = 0 in x = g(x). Vervolgens reken je net zo lang een nieuwe + x uit totdat het verschil met de vorige x kleiner is dan een + bepaalde tolerantie. Deze methode is niet in algemene zin + voor de computer te programmeren omdat de computer het + probleem niet kan herschrijven. Deze methode is sowieso niet + handig omdat de herschrijving aan de voorwaarde moet voldoen + dat g'(x) < 1 op een bepaald interval. Indien g'(x) > 1 dan + zal het divergeren. + + + N E W T O N - R A P H S O N + + Je neemt de raaklijn aan de functie in het punt (x,f(x)) en + je nieuwe benadering is het snijpunt van deze lijn met de + x-as. Dit herhaal je totdat de nieuwe benadering minder dan + een bepaalde tolerantie verschilt van de vorige. + + Deze methode heeft twee nadelen: je hebt de afgeleide nodig + om de raaklijn te bepalen en het gaat mis als f'(x) + toevallig 0 wordt. Dan is de raaklijn horizontaal en is er + geen snijpunt met de x-as. + + + S E C A N T + + Deze methode is gelijk aan de Newton-Raphson methode, alleen + schat je de raaklijn als een rechte lijn door het vorige + punt en het huidige punt. Hoewel de afleiding anders is, is + het resultaat hetzelfde als de false position methode. + + + T E N S L O T T E + + De volgende keer ga ik het waarschijnlijk hebben over + numeriek integreren. Ook daar zijn een paar handige + algoritmes voor die eenvoudig in BASIC kunnen worden + geprogrammeerd. Tot dan! + + Stefan Boer diff --git a/sunrise_special/6/Clock en batterij memory.md b/sunrise_special/6/Clock en batterij memory.md new file mode 100644 index 0000000..7ac59c8 --- /dev/null +++ b/sunrise_special/6/Clock en batterij memory.md @@ -0,0 +1,427 @@ + C L O C K E N B A T E R I J M E M O R Y + + + In de MSX2 en hoger zit een CLOCK-IC voor het bijhouden van + de tijd en datum. Omdat dit IC door een baterij wordt + gevoed, blijft het aktief ook als de computer wordt + uitgeschakeld. Ook is er een kleine hoeveelheid RAM voor het + bewaren van o.a de prompt en diverse screen instellingen. + + + C L O C K - I C F U N C T I E S + + Het IC heeft de volgende 3 functies: + + - CLOCK functies: + + - Bijhouden, lezen en schrijven van de TIJD en DATUM + - Keuze uit 24-uur/12-uur klok aanduiding. + - Bijhouden aantal dagen van de maand, en schrikkeljaar. + + - ALARM functies: + + - Als de actuele tijd is gelijk wordt aan de alarm tijd, + zal de clock een signaal doorgeven. + + - Baterij geheugen: + + - Bevat 26 x 4 bits registers, met diverse data + - MSX2 bewaart de volgende data in zijn geheugen: + + 1. "Adjust" + 2. Scherm keuze, "WIDTH" en kleuren + 3. "BEEP" patroon en volume + 4. Opstart scherm kleur + 5. Land code + 6. Paswoord + 7. BASIC prompt + 8. Opstart titel + + Van de laatste 3 (pasword, promt, title) kan er slechts 1 + aktief zijn. + + + S T R U K T U U R V A N C L O C K - I C + + Het clock-IC bestaat uit vier blokken zoals hieronder + afgedrukt. Elk blok bestaat uit 13 registers welke 4 bits + bevatten (LSB). Deze registers worden gespecificeerd van 0 + to 12. Daarnaast zijn er nog drie control registers (MODE, + TEST en RESET), waarmee diverse akties kunnen worden + uitgevoerd (register 13 to 15). De register in blokken + (0-12) en het MODE register (13) kunnen worden gelezen en + beschreven. De TEST (14) en RESET (15) registers kunnen + alleen worden beschreven. + + Blok 0 Blok 1 Blok 2 Blok 3 + (CLOCK) (ALARM) (RAM-1) (RAM-2) + 13 registers 13 registers 13 registers 13 registers + + r#13 MODE + r#14 TEST (write only) + r#15 RESET (write only) + + + M O D E R E G I S T E R + + Dit register heeft 3 functies, te weten: + + - Blok selecteren + Om een register te lezen of te beschrijven (0-12), moet er + van te voren wel worden aangegeven met welk blok er moet + worden gewerkt. De laagste twee bits bevatten het blok + nummer. Waneer eenmaal een blok is geselecteerd, kan een + register meerdere malen worden gebruikt zonder daarna weer + het blok nummer op te geven. + + Registers #13, #14 en #15 zijn altijd toegankelijk + onafhankelijk van het blok nummer. + + - ALARM aan/uit + Om het alarm aan of uit te zetten, moet bit 2 worden gezet + of gereset. "0" is uit. Omdat de standaard MSX2 de alarm + functies niet gebruikt, zal er niets gebeuren als de alarm + tijd is bereikt. Er wordt alleen ergens een signaal gegeven. + + - Stop CLOCK teller + Door bit 3 van het MODE register te resetten, zal de + klok-seconden teller stil gaan staan, en niet meer verder + tellen. Door dit bit weer te zetten, zal het tellen weer + doorgaan. + + MODE register opbouw: + + b3 b2 b1 b0 + r#13 TE AE M1 M0 + + M1/M0: Blok nummer + AE: Alarm aan/uit (0 is uit) + TE: Klok (0 is uit, in seconden) + + + T E S T R E G I S T E R + + Dit register (r#14) wordt gebruikt voor het direct verhogen + van de hoogste teller, en om na te gaan of de overdracht van + de tijd en datum juist is gedaan. Door een van de bits hoog + te maken, wordt er een puls van 2^14 (is 16384) Hz + doorgegeven aan de dag, uur, minuut en seconden tellers. + + TEST register opbouw: + + b3 b2 b1 b0 + r#14 T3 T2 T1 T0 (puls bits) + + T3: Dag + T2: Uur + T3: Minuut + T4: Seconden + + + R E S E T R E G I S T E R + + Het reset register (r#15) heeft de volgende functies: + + - Alarm reset + Als dit bit hoog wordt gemaakt, worden alle alarm register + ge-reset (nul). + + - Seconden afronden + Het klok IC telt ook in honderdste seconden. Om de seconden + exact te kunnen zetten, kunnen de nivo's voor de hele + seconden worden gereset (nul). Maak het bit hoog voor het + resetten. + + - Clock puls aan/uit + Het clock IC genereerd ook 2 lage pulsen. Een puls van 16Hz + of een puls van 1Hz. Door bit 2 "0" te maken zal de 16Hz + puls aan zijn. Door bit 3 "0" te maken zal de 1Hz puls aan + zijn. De MSX ondersteund dit echter niet, waardoor er + feitelijk niets mee kan worden gedaan. + + Reset register opbouw: + + b3 b2 b1 b0 + r#15 C1 C16 CR AR + + C1: 1Hz puls + C16: 16Hz puls + CR: Reset fracties voor seconden + AR: Reset alarm functies. + + + B L O K 0 / 1 + + T I J D , D A T U M E N A L A R M + + Blok schema: + + BLOK 0: KLOK + reg. Omschrijving. Dec. b3 b2 b1 b0 + (0) Seconden 1e x x x x 00-59 + (1) Seconden 2e . x x x + (2) Minuten 1e x x x x 00-59 + (3) Minuten 2e . x x x + (4) Uren 1e x x x x 00-23 + (5) Uren 2e . . x x + (6) Dag van week 1 . x x x 01-07 + (7) Dag 1e x x x x 01-31 + (8) Dag 2e . . x x + (9) Maand 1e x x x x 01-12 + (10) Maand 2e . . . x + (11) Jaar 1e x x x x 00-255 + (12) Jaar 2e x x x x (+80) + + Bits aangegeven met "." zijn altijd nul, en kunnen niet + worden gemodificeerd. + + Blok nul wordt gebruikt voor het lezen/schrijven van de tijd + en datum. De data is in max. 4 bits opgeslagen, waardoor een + ASCII teken in twee delen wordt opgesplitst. Bijvoorbeeld + een tijd eenheid bestaat uit 1x4 bits en 1x3 bits. Door bij + deze bits het ASCII teken "0" er bij op te tellen, onstaat + er 1 decimaal van een getal. + + Voorbeeld: We willen de tijd in uren weten. + Als we uit blok 0 dan de volgende register lezen; + + (5) +"0" 2e decimaal (wordt als eerste afgedrukt!) + (4) +"0" 1e decimaal (wordt als tweede afgedrukt!) + + Door deze twee ASCII waarden achterelkaar af te drukken, is + de tijd in uren bekend. + + Het jaar dat wordt bijgehouden, start bij 1980, dus moet er + bij de tweede decimaal "8" bij worden opgeteld in plaats van + "0". De datum zoals we die hier in Nederland afdrukken is + meestal van de volgende orde: + + Dag/Maand/Jaar + + De dag van de week wordt bijgehouden van 0 tot en met 6. + Deze wordt vernieuwd waneer de datum ook wordt vernieuwd. + + + BLOK 1: ALARM + reg. Omschrijving. Dec. b3 b2 b1 b0 + (0) ---- 1e x x x x + (1) ---- 2e . x x x + (2) Minuten 1e x x x x 00-59 + (3) Minuten 2e . x x x + (4) Uren 1e x x x x 00-23 + (5) Uren 2e . . x x + (6) Dag van week 1 . x x x 01-07 + (7) Dag 1e x x x x 01-31 + (8) Dag 2e . . x x + (9) ---- 1e x x x x + (10) 12 of 24 Uur 2e . . . x + (11) Schrikel jaar 1e . . x x 00-03 + (12) ---- 2e x x x x + + Het alarm kan alleen worden opgegeven in dagen, uren en + minuten. Dit blok bevat ook nog 2 register die betreking + hebben op de tijd aanduiding, en het schrikkeljaar. + + - 12 of 24 uur selectie + Er kunnen twee klok tijden worden geselecteerd; de een is + een 24-uurs aanduiding, welke de tijd in de middag/avond + weergeeft als 13:00, en de andere en een 12-uurs aanduiding, + welke het als 1 p.m. aangeeft. Door bit 0 van r#10 van blok + 1 hoog te maken, wordt er voor 24-uur gekozen. + + b3 b2 b1 b0 + r#10/B1 . . . TM + + TM: 0: 12 uren, 1: 24 uren. + + Als er voor 12-uren wordt gekozen, zal b1 van r#5 (blok 1) + aangeven of het 's morgens of 's middags is. + + b3 b2 b1 b0 + . . HR . + + HR: 0: Voor de middag (am), 1: namiddag (pm). + + - Schrikkeljaar. + + Register #11 houd bij of er dit jaar een schrikkel jaar is + of niet. Als dit zo is, zal de inhoud van dit register nul + zijn. Aangezien een schrikkeljaar om de vier jaar plaats + vindt (februari heeft dan 29 dagen), zal dit een 2 bits + teller zijn (0-3). + + + I N H O U D C L O C K - M E M O R Y + + blok twee en drie van het clock-IC wordt gebruikt voor de + 13x4 bits baterij geheugen blokken. Deze zien er als volgt + uit: + + - Inhoud blok 2 + + reg. b3 b2 b1 b0 + (0) -- ID -- + (1) X-adjust (-8 tot +7) + (2) Y-adjust (-8 tot +7) + (3) . . Interl Screen + (4) Width (laage bits) + (5) Width (hoge bits) + (6) Voorgrond kleur + (7) Achtergrond kleur + (8) Rand kleur + (9) Cass spd Pinter Key Clk Key ON/OFF + (10) BEEP soort Beep Volume + (11) . . Titel kleur + (12) Native Code + + Ik denk dat dit blok wel voor zich spreekt. + + - Inhoud blok 3 + + Dit blok bestaat ook nog eens uit 3 sub-bloks. Deze kan + worden gekozen door een ID code naar block drie te + schrijven, hierna kan een sub-blok worden + gelezen/beschreven. + + Sub-blok 1, openings titel (6 karakters) + reg. b3 t/m b0 + (0) ID:0 + (1) 1e karakter (laag) + (2) 1e karakter (hoog) + . + . + . + (11) 6e karakter (laag) + (12) 6e karakter (hoog) + + Sub-blok 2, password + reg. b3 t/m b0 + (0) ID:1 + (1) gebruik ID:1 + (2) gebruik ID:2 + (3) gebruik ID:3 + (4) Paswoord * + (5) ,, + (6) ,, + (7) ,, + (8) Key cartridge flag + (9) Key cartridge waarde + (10) ,, + (11) ,, + (12) ,, + + * Het paswoord word gecompreseerd opgeslagen in 4x4 bits. + Hoe dit wordt opgeslagen is mij niet bekend. Waar de rest + voor dient zou ik ook precies weten. Gezien ik deze blokken + toch nooit gebruik. + + Sub-blok 3, Basic prompt (6 karakters) + reg. b3 t/m b0 + (0) ID:2 + (1) 1e karakter (laag) + (2) 1e karakter (hoog) + . + . + . + (11) 6e karakter (laag) + (12) 6e karakter (hoog) + + De registers van sub-blok 1 & 3 spreken voor zichzelf. + + + T O E G A N G T O T H E T C L O C K - I C + + In het MSX SUB-ROM Bios zitten 2 routines voor de toegang + van deze clock IC. Om deze aan te roepen moet de inter-slot + call routine &h1F5 worden gebruikt. Deze routines gebruiken + de volgende entries: + + - REDCLK (01F5/SUB), Read CLOCK-IC data + In: C, register en block. + Uit: A, register data. + Funtie: Lees CLOCK-IC register. + + - WRTCLK (01F9/SUB), Write CLOCK-IC data + In: C, register en block. + A, register data. + Funtie: Schrijf naar CLOCK-IC register. + + Het C register bevat twee waarden; het register/sub-blok en + het blok nr. De volgende bits worden gebruikt: + + b7 b6 b5 b4 b3 b2 b1 b0 + C reg. . . M1 M2 A3 A2 A1 A0 + + M1/M2: Blok nr. + A3-A0: Register/sub-blok nr + + Maar natuurlijk kan er ook gebruik worden gemaakt van de OUT + poorten (dit doen de BIOS routines ten slotte ook). Maar + aangezien de BIOS routines vaak meer doen dan gedaan hoeft + te worden, kunnen er beter eigen routines worden gebruikt. + Om namelijk meerdere keren een register uit het zelfde blok + te kunnen lezen/schrijven, hoeft er maar 1 keer te worden + opgegeven wat voor (sub) blok er moet worden gebruikt. Bij + de bios routines wordt dit altijd het blok gezet, wat dus + tijds verlies is. + De poorten die het IC gebruikt zijn: + + &hB4 - register/block nr + &hB5 - Data. + + Hieronder zijn enkele routines geplaats als voorbeeld voor + het lezen, schrijven van het IC. + + ;+----- Clock Routines -----+ + ; written by: SHADOW from FUZZY LOGIC. + ; last update: 29/02/94 for sunrise special. + + ; Read Clock_Register + ; note: Set block nr with "SC_BLK" first! + ; In: A, Clock register/block ID to read + ; Out: A, clock data + RD_CLK: DI + OUT (&HB4),A + IN A,(&HB5) + AND &H0F + EI + RET + + ; Write Clock_Register + ; note: Set block nr with "SC_BLK" first! + ; In: A, clock register/block ID to write + ; B, register data + WR_CLK: DI + OUT (&HB4),A + IN A,(&HB5) + AND &H0F + EI + RET + + ; Set Clock_Block + ; In: B, bloc nr (0-3) + SC_BLK: CALL RC_MOD + AND &H0C ; save count/alarm bits + OR B ; add block + DI + OUT (&HB5),A + EI + RET + + ; Read Clock_Mode reg + RC_MOD: LD A,13 + JP RD_CLK + + + Dit zijn feitelijk alle routines die nodig zijn voor het + gebruik van de CLOCK-IC. Op deze special staat een file + "CLOCK-IC.asc" die een paar routines bevat die de tijd en + datum op het beeld zet. + Voor het beschrijven van het MODE register is het wel van + belang dat de rest van de bits bewaard blijven, dus lees + eerst even dit register uit met "RC_MOD". + + Mocht iemand weten hoe het pasword-sub-blok wordt beruikt, + laat het dan even weten, want zelf sta ik voor een raadsel. + + R�man van der Meulen diff --git a/sunrise_special/6/Cursus modula deel 1.md b/sunrise_special/6/Cursus modula deel 1.md new file mode 100644 index 0000000..dda23f5 --- /dev/null +++ b/sunrise_special/6/Cursus modula deel 1.md @@ -0,0 +1,282 @@ + C U R S U S M O D U L A - 2 ( 1 ) + + + I N L E I D I N G + + Aangezien het niet mogelijk is om in ��n deel iemand die + helemaal niets van Turbo Pascal weet Modula-2 te leren ga ik + de volgende keer van nul af aan beginnen. Dit deel van de + cursus is daarom bedoeld voor MSX'ers die al ervaring hebben + met Turbo Pascal. + + Als je niet wilt wachten tot Special #7 dan kun je + natuurlijk altijd eens inloggen bij de Games BBS, daar is + een Engelstalige Modula-2 cursus te vinden en een flinke + hoeveelheid voorbeeldsources. Bovendien is er een .PMA te + vinden met uitleg van Pierre Gielen over het naar modulevorm + overzetten van ML-routines. + + + O P B O U W + + Onderstaand voorbeeld laat de opbouw van een Modula-2 source + zien. Het programma vult een array met wortels en drukt dat + array vervolgens af. Wat het programma doet is niet boeiend, + het gaat om de opbouw. + + + MODULE Opbouw; + + (* + Auteur : Stefan Boer + Versie : 1.0 + Last updated: 09/06/94 + *) + + + FROM MathLib IMPORT + Sqrt; + + + CONST + AantalWortels = 10; + + + TYPE + WortelIndexType = CARDINAL [1..AantalWortels]; + WortelLijstType = ARRAY WortelIndexType OF REAL; + + + VAR + WortelLijst: WortelLijstType; + + + PROCEDURE BerekenWortels(VAR WortelLijst: WortelLijstType); + + VAR + i: WortelIndexType; + + BEGIN + FOR i := 1 TO AantalWortels DO + WortelLijst[i] := Sqrt(FLOAT(i)); + END; + END BerekenWortels; + + + PROCEDURE PrintWortels(WortelLijst: WortelLijstType); + + VAR + i: WortelIndexType; + + BEGIN + FOR i := 1 TO AantalWortels DO + WRITELN(WortelLijst[i]); + END; + END PrintWortels; + + + (* Hoofdprogramma *) + + BEGIN + BerekenWortels(WortelLijst); + PrintWortels(WortelLijst); + END Opbouw. + + + Merk op dat de definitie van MathLib afwijkend is van wat + Wirth voorschrijft bij Turbo Modula-2! Wirth noemt hem + MathLib0 en de vierkantswortel heet bij hem sqrt, niet met + een hoofdletter dus! + + Pascalkenners zal de volgende dingen opvallen: + + - De source begint niet met PROGRAM maar met MODULE + - ENDs van modules en procedures zijn gelabeld + - De syntax van het FOR-statement is anders + - Sqrt moet worden ge�mporteerd + - Declaratie van subrange en array gaat anders + + Ik zal nu een aantal verschillen tussen Turbo Pascal en + Turbo Modula-2 bespreken. + + + C O M P O U N D S T A T E M E N T + + Bij Turbo Pascal ziet een IF statement er bijvoorbeeld zo + uit: + + IF boolean expressie THEN + statement1 + ELSE + statement2; + + Om toch meerdere statements te kunnen gebruiken heeft Wirth + het compound statement bedacht, door BEGIN en END om een + groep statements te zetten worden ze samen ��n statement. + + Dit kan erg verwarrend zijn, vooral als je een zootje maakt + van de layout. Bijvoorbeeld: + + IF a = 3 THEN + WRITE('a is 3'); + WRITE('hallo'); + + Door de layout suggereer ik hier dat het tweede WRITE + statement alleen wordt uitgevoerd als a gelijk is aan 3. Dit + is niet zo, alleen het eerste WRITE statement hoort bij de + IF. De juiste Pascal formulering zou zijn: + + IF a = 3 THEN + BEGIN + WRITE('a is 3'); + WRITE('hallo'); + END; + + Hier hebben we dus een compound statement gebruikt. In + Modula-2 is het veel logischer: + + IF boolean expressie THEN + statement sequence 1 + ELSE + statement sequence 2 + END; + + Waarbij een 'statement sequence' bestaat uit 0 (!), 1 of + meer statements! Er staat dus NOOIT een BEGIN en ALTIJD een + END! Bovendien MOGEN er in Modula-2 altijd ; geplaatst + worden. Bij Pascal is dat niet zo. Bijvoorbeeld: + + IF a = 3 THEN + WRITE('hallo'); + ELSE + WRITE('doei'); + + geeft een foutmelding in Pascal, de ; achter WRITE('hallo') + is in Pascal niet toegestaan. In Modula-2 moet er natuurlijk + nog een END achteraan en de puntkomma mag wel! (Maar hoeft + niet.) + + Omdat een puntkomma achter een statement in Modula-2 altijd + mag zet ik er ook altijd ��n, dan kan ik me nooit vergissen! + + Bij WHILE, FOR en WITH gaat het net zo. Dus: + + WHILE boolean expressie DO + statement sequence + END; + + FOR loopvariable := startwaarde TO eindwaarde DO + statementsequence + END; + + WITH record-variabele DO + statementsequence + END; + + + T Y P E S + + Turbo Modula-2 kent de volgende atomaire types: + + BITSET standaard settype + BOOLEAN waar/niet waar + CHAR character + CARDINAL 0, 1, 2, ..., 65535 + INTEGER -32768, ..., 0, ..., 32767 + LONGINT + REAL single precision floating point (6 cijfers) + LONGREAL double precision floating point (14 cijfers) + + Voorbeelden van simple types: + + subrange: IndexType = CARDINAL [1..10]; + enumeration: StatusType = (Slecht, Matig, Redelijk, Goed); + + Voorbeelden van gestructureerde types: + + record: PatientType = RECORD + Temperatuur: REAL; + Bloeddruk : REAL; + END; + array: LijstType = ARRAY IndexType OF PatientType; + set: Verzameling = SET OF IndexType; + + Verder zijn er nog pointertypes en procuduretypes, maar daar + kom ik in een later deel van de cursus nog wel eens op + terug. + + + F U N C T I E S + + In Pascal ziet een functie er bijvoorbeeld als volgt uit: + + FUNCTION Kwadraat(x: REAL): REAL; + + BEGIN + Kwadraat := x * x; + END; + + In Modula-2 wordt dit: + + PROCEDURE Kwadraat(x: REAL): REAL; + + BEGIN + RETURN x * x; + END Kwadraat; + + Er zijn 3 belangrijke verschillen: + + 1) PROCEDURE in plaats van FUNCTION + 2) RETURN in plaats van functienaam := + 3) Bij een Modula-2 functie staan altijd haakjes, ook als er + geen parameters zijn! + + Met RETURN wordt ook meteen de functie be�indigd, RETURN + zonder iets erachter kan in een gewone procedure worden + gebruikt om uit de procedure te springen. + + + M C C A R T H Y + + Modula-2 gebruikt McCarthy evaluatie bij het evalueren van + boolean expressies. Dit komt erop neer dat de boolean + expressie niet verder wordt ge�valueerd dan nodig is. In + Pascal wordt de boolean expressie altijd helemaal + ge�valueerd! + + McCarthy evaluatie heeft geen nadelen, de voordelen zijn dat + het sneller is en dat onderstaand statement altijd goed + gaat: + + IF (n = 0) OR (a / n > 10) THEN ... + + Bij Turbo Pascal gaat dit fout, want bij het uitrekenen van + a / n wordt er door 0 gedeeld! Bij Modula-2 gaat het goed, + want als n gelijk is aan 0 dan wordt a / n niet meer + uitgerekend! + + + S T R E N G + + Modula-2 is strenger bij de controle op types. Operaties + zoals aftrekken, vermenigvuldigen, etc. mogen alleen maar + worden gedaan op gelijke types!!! + + Het onderstaande mag dus niet! + + VAR + x: INTEGER; + y: CARDINAL; + + WRITE(x*y); + + + T E N S L O T T E + + Dit waren in het kort de belangrijkste verschillen tussen + Turbo Modula-2 en Turbo Pascal. De volgende keer ga ik vanaf + het begin beginnen met een cursus gestructureerd + programmeren in Modula-2. + + Tot dan! + Stefan Boer diff --git a/sunrise_special/6/Een muis met een staartje.md b/sunrise_special/6/Een muis met een staartje.md new file mode 100644 index 0000000..d6602eb --- /dev/null +++ b/sunrise_special/6/Een muis met een staartje.md @@ -0,0 +1,354 @@ + E E N M U I S M E T E E N S T A A R T J E + + + (I/O Interface 2) + + Inderdaad, dit verhaal krijgt een staartje. Er is al eens + een tekst geschreven over het aansturen (en vooral lezen!) + van de mouse. Er zaten alleen wat nadelen aan de routine die + toen werd geschreven. Het werkte alleen in de Z80 stand, en + was nogal 'gevaarlijk' geschreven, doordat er rechtstreeks + in de routines werd ge'poked' voor het uitlezen van zowel + poort 1 als poort 2. + + In deze tekst hoop ik wat meer duidelijkheid te kunnen + scheppen in het hele I/O gebeuren wat betreft de mouse, en + een betere routine te leveren (die NIET gebruik maakt van de + standaard MSX ROM BIOS!). Er wordt hier gebruikt gemaakt van + de PSG poorten, dus raad ik aan de tekst over het gebruik + van de joystick in ML (special #5) eerst (nog) eens door te + lezen. + + + M E N N E M E . . + + Om een mouse te gebruiken moet er toch eerst worden gezocht + of er wel een mouse aanwezig is. Deze kan aangesloten zijn + in zowel poort 1 als 2. Om aan te geven in welke poort we + willen werken, moeten we van PSG r#15 het 6e bit (lees ook + artikel over joysticks) aan of uit zetten. (0=poort 1, + 1=poort 2). + + Om aan te geven dat we gebruik willen gaan maken van de + mouse, moeten we (weer afhankelijk van welke poort) bit 4 of + bit 5 van r#15 zetten. Deze bits zijn verbonden met de 8e + pen van de game-poorten (deze zitten, zoals bekend?, + hardware matig aan de buitenkant van uw MSX). + + Als er aan uw MSX geen mouse hangt, maar een programma neemt + aan van wel, en er wordt mouse data gelezen, bijvoorbeeld in + en tekenprogramma, dan zal het teken-pijltje langzaam met + stappen van 1 naar de rechter onderhoek van uw scherm + glijden. Van dit proces kunnen we gebruik maken om te kijken + of er wel of niet een mouse aanwezig is! + + Als we een aantal keren gaan kijken of de mouse offsets X en + Y iedere keer met 1 worden verhoogt, dan zal er blijkbaar + geen mouse aanwezig zijn. Als we dit 1 keer gaan testen, dan + is er het gevaar dat de gebruiker de mouse beweegt op het + moment van testen, en dat deze beweging precies overeenkomt + met het al eerder genoemde proces. Dus is het verstandig om + meerdere malen dit te gaan testen. Want het is praktisch + onmogelijk om precies de X en Y met 1 te laten verhogen voor + meerdere malen achter elkaar! + + + Z 8 0 O F R 8 0 0 + + Om een mouse te lezen, moeten er vertragings routines worden + gebruikt, omdat de mouse een relatief traag apparaatje is + ten opzichte van de CPU (Z80 of R800). + Met andere woorden: Er moet gewacht worden op de mouse tot + dat deze klaar is met het verzenden van data. Daar er geen + 'strobe' (klaar voor aktie signaal) wordt gegeven, moeten we + gewoon de CPU een tijdje laten wachten. + + Hier stuiten we op een probleem. We kunnen namelijk wachten + door middel van interrupts of gewoon een vertragings lus. + Maar een interrupt duurt veel te lang voor het wachten op de + muis (1/50 of 1/60 seconde). Daarom kiezen we voor een + vertagings lus. Maar omdat de Z80 op 3.5 MHz loopt en de + R800 op 7,4 MHz, moeten we 2 verschillende routines maken. + Tijdens het installeren van de mouse kunnen we hier gewoon + even kijken wat voor CPU er aan boord is en na aanleiding + van dit een pointer 'poken'. + + Het feitelijk uitlezen gaat via de PSG poorten. De data die + gelezen kan worden zijn altijd in afstanden (offsets) ten + opzichte van de laatst gelezen waarde. Dus de afstand dat u + de mouse beweegt. Door deze bij de vorige coordinaten op de + tellen, hebt u de nieuwe coordinaten. + De data die wordt gegeven zijn slechts 4 bits, daar er 8 + nodig zijn voor het bereik van 0-255 moet er dus 2 keer + gelezen worden om een 8 bits offset te krijgen. Dit kan door + gewoon twee keer achter elkaar r#15 te lezen. De eerste keer + worden de 4 hoogste bits gegeven, daarna de 4 laagste. De + offsets worden in bits 0-3 geplaats. De mouse doet er echter + langer over om de 4 hoogste X-offset bits door te geven dan + de 4 laagste, dus zal de eerste keer dat r#15 wordt gelezen + langer moeten worden gewacht. De Y offsets worden altijd + even snel doorgegeven. Een voorbeeld van twee wacht + routines: + + ; - Delay routs - + ; Z80. + ; In: B, delay length + DL_Z80: DJNZ DL_Z80 + RET + + ; (R800) + ; In: C, delay lenth + DL_R80: IN A,(&HE6) ; turbo R timer + LD B,A + DR80.0: IN A,(&HE6) + SUB B + CP C + JP C,DR80.0 + RET + + Bij de MSX tubo R wacht routine wordt gebruikt gemaakt van + een razend snelle teller die in deze pracht machine zit + ingebouwd. Bij de eerste keer uitlezen van de mouse zullen + de volgende vertragingen moeten worden gebruikt (minimaal): + Z80 - B,40 + R800 - C,20 + + De volgende keren dat gelezen moet worden kan de vertraging + korter zijn namelijk: + Z80 - B,7 + R800 - C,6 + + + P A D D L E U I T L E Z E N + + De volgende data gebruiken we bij de mouse acties. Deze + staan origineel ook in het System variabelen gebied, dus + waarom zouden we die niet gebruiken? + + ; Mouse vars. + MOUSID: EQU &HFAFD ; ID code: 0=Niet aanwezig + MSEOFS: EQU &HFAFE ; Mouse offsets X en Y + MOUSXY: EQU &HFB00 ; Mouse X en Y positie + MSEPRT: EQU &HFC82 ; Mouse Poort (0=niet, + ; &H10=poort 1, &H60=poort2) + + + De data die de padle geeft is ook nog een keer negatief dus + als de mouse naar boven wordt bewogen, zal bijvoorbeeld de Y + offset +20 zijn in plaats van -20. Zowel de X als de Y + offsets zijn negatief. + Een dergelijke routine om de beide offsets te lezen kan er + als volgt uit zien: + + ; Get paddle offset. + ; In: [MSEPRT], port nr. (see mouse vars.) + ; Out: [MSEOFS]/HL, YYXX ofs. (A, Y ofs.) + GETPAD: PUSH BC + PUSH DE + + LD DE,(MSEPRT) ; E=Mouse poort. + LD A,15 ; Lees PSG r#15 + CALL RD_PSG + AND &B10001111 ; bewaar rest bits. + OR E ; Maak nr bit "1" + LD E,A + + ; X offset + LD B,40 ; Eerste vertraging Z80 + LD C,20 ; ,, ,, R800 + CALL GPAD.2 ; MSB + CALL GPAD.0 ; LSB + LD L,A ; L=X offset + + ; Y offset + CALL GPAD.1 ; MSB + CALL GPAD.0 ; LSB + LD H,A ; H=Y offset + LD (MSEOFS),HL ; bewaar beide offsets + + EI + POP DE + POP BC + RET + + ; Shift bits (LSB -> MSB), read LSB and make offset neg. + GPAD.0: RLCA + RLCA + RLCA + RLCA + AND &HF0 + LD D,A + CALL GPAD.1 ; Lees LSB + OR D ; Voeg MSB hier aan toe + NEG ; Maak offset negatief. + RET + + ; Read paddle data + ; In: [MSEPRT], mouse port (see mouse vars.) + ; (B/C, delay first time -> only in GPAD.2) + ; Out: A, offset in LSB + GPAD.1: LD BC,&H0706 ; Vertraging variables + GPAD.2: LD A,15 ; Schrijf naar r#15 + CALL WR_PSG + LD A,(MSEPRT) + AND &H30 ; Alleen mouse bits + XOR E + LD E,A + GP_DL#: CALL xxxx ; Hier wordt de vertragings + pointer gepoked tijdens + de mouse installatie + (Z80 of R800) + LD A,14 ; Lees r#14 (offset data) + CALL RD_PSG + AND &H0F ; alleen LSB + RET + + Routines voor het schrijven of lezen van de PSG kunnen er + als volgt uit zien: + + ; Read PSG. + ; In: A, port nr + ; Out: A, data + RD_PSG: DI + OUT (&HA0),A + IN A,(&HA2) + EI + RET + + ; Write to PSG. + ; In: A, port nr. E, port data + WR_PSG: DI + OUT (&HA0),A + LD A,E + OUT (&HA1),A + EI + RET + + Deze laatste twee routines zijn feitelijk het zelfde als die + in het MSX ROM BIOS aanwezig zijn, maar aangezien ik hier + (liever) geen gebruik van maak heb ik ze hier maar + bijgevoegd. + + Nu hebben we dus een routine die de paddle data kan lezen. + Om het vertragins pointer adres te poken, moet er nog een + mouse installatie routine worden geschreven. Deze moet dus + kijken of we met een Z80 of een R800 CPU te maken hebben. + Door het adres &h2D uit te lezen weten we of we met een + turbo R computer of een MSX 1/2/2+ te maken hebben. Indien + het om een MSX turbo R gaat moet er ook nog gekeken worden + in welke CPU mode hij (of is het een zij?) op dit moment + staat. + + ; Install Mouse + MOUSIN: LD A,255 + LD (MOUSID),A + LD HL,DL_Z80 ; vertraging pointer Z80 + LD A,(&H2D) ; turbo R ? + CP 3 ; nee.. + JP C,MSIN.0 + CALL &H0183 ; R800 aan? + AND A + JP Z,MSIN.0 ; nee.. + LD HL,DL_R80 ; ja, turbo R wacht routine + MSIN.0: LD (GPW_#A+1),HL + RET + + Om te kijken in welke CPU mode de turbo R staat heb ik nu + wel voor de ROM routine gekozen. Om de CPU te wisselen moet + er namelijk van alles worden bewaard zoals de register en + stack pointer etc. Om de CPU te lezen hoeft dit niet, maar + aangezien ik de CPU switch routine ook niet heb herschreven, + leek mij het hier ook niet echt nootzakelijk. + + + M O U S E D E T E C T I E + + Nu zijn alle routines klaar voor het lezen van de paddle + waarde. Deze routines kunnen we nu gebruiken voor + bijvoorbeeld het controleren of de mouse aanwezig is in een + game-poort. De volgende routine lost dit voor ons op: + + ; Check mouse. + ; Out: [MOUSEID]: 0=not found, 255=found and installed. + ; Cy: 0=found, 1=not found. + CHMOUS: CALL MOUSIN ; instaleer wacht lus. + LD A,&H10 ; probeer eerst poort 1... + LD (MSEPRT),A + CALL CHMS.0 + JP NC,MOUSIN ; gevonden. + + LD A,&H60 ; niet, dan poort 2 + LD (MSEPRT),A + CALL CHMS.0 + JP NC,MOUSIN ; gevonden. + + XOR A ; niet gevonden. + LD (MOUSID),A + LD (MSEPRT),A + SCF ; Cy=1 + RET + + CHMS.0: LD B,40 ; kontroleer 40 x + CHMS.1: PUSH BC + CALL G_PADL ; Y-offset + CP 1 ; stap+1? + JP NZ,CHMS.2 ; nee, dus mouse aanwezig + LD A,L ; X-offset + CP 1 ; stap+1? + JP NZ,CHMS.2 ; nee, dus mouse aanwezig + POP BC ; nog een keer.. + DJNZ CHMS.1 + SCF ; Cy:1 (niet gevonden) + RET + CHMS.2: POP BC ; gevonden + AND A ; Cy:0 + RET + + Na het aanroepen van deze routine kan er op drie manieren + worden gecontroleerd of de mouse al dan niet aanwezig is. + Als de carry (Cy) hoog is, zal deze niet zijn gevonden. De + variable MOUSID zal "0" zijn als de mouse niet aanwezig is + (255 is wel aanwezig). Ook kan de variable MSEPRT worden + gelezen. Is deze "0" dan is de mouse niet gevonden, anders + bevat deze de mouse poort nummer data. + Meer is eigenlijk niet nodig, om de X/Y positie te + verkrijgen kunnen gewoon de X en Y offsets bij de originele + coordinaten worden op geteld. Een routine die dat ook voor + ons regelt: + + ; Read any mouse, and set X,Y pos. + ; Out: [MOUSXY]/HL, XXYY position. + ; Cy: 1, mouse not found + RDMOUS: LD HL,0 + LD (MSEOFS),HL + LD A,(MOUSID) ; Controleer of er een mouse + AND A ; aanwezig is. + SCF ; Zet carry flag. + RET Z + + CALL GETPAD ; Lees paddle + LD A,(MOUSXY) ; Originele X positie. + ADD A,L ; + X offset + LD L,A + LD (MOUSXY),A + LD A,(MOUSXY+1) ; Originele Y positie. + ADD A,H ; + Y offset + LD H,A + LD (MOUSXY+1),A + AND A ; Wis carry flag + RET + + Met deze routines moet het mogelijk zijn om 100% gebruik te + kunnen maken van de mouse. De twee vuurknoppen worden + natuurlijk op de zelfde manier gelezen als de joystick (zie + ook I/O interface deel 1, RDTRG1 / RDTRG2). + + Ik stimuleer het enorm om in software pakketten de mouse + zoveel mogelijk te kunnen gebruiken. Zowel in utilities als + in demos! (zoals bijvoorbeeld in de MB muzax reeks). Want de + mouse is toch een prima stukje hardware voor interactieve + doeleinden. In screen 0 kan ook uitstekend de mouse worden + gebruikt. Deel gewoon de X en Y coordinaten door 8 voor de + juiste posities. + + R�man van der Meulen diff --git a/sunrise_special/6/Files voor MSX View.md b/sunrise_special/6/Files voor MSX View.md new file mode 100644 index 0000000..6b06e6d --- /dev/null +++ b/sunrise_special/6/Files voor MSX View.md @@ -0,0 +1,23 @@ + F I L E S V O O R M S X - V I E W + + + Jan van Valburg heeft de volgende files gemaakt of er een + Nederlandse handleiding bijgemaakt: + + VIEW-01.PMA: Een printerdriver voor de EPSON LQ-400. + VIEW-02.PMA: Een programma om MIDI-files af te spelen onder + MSX-View. + VIEW-03.PMA: Hiermee is het mogelijk om C programma's voor + onder MSX-View te schrijven. + VIEW-04.PMA: Een aantal stempels voor MSX-View. + VIEW-05.PMA: Een demoversie van de patch naar Engels van + MGF. + + De volgende 2 files zijn tenslotte nog andere applicaties + voor MSX-View, compleet in het Japans: + + BOMBS.PMA : Bombsweeper voor MSX-View. + MEIDOSS.PMA: Een programma waarmee iets met samples mogelijk + is. + + Kasper Souren diff --git a/sunrise_special/6/Gestruktureerd programmeren in ML deel 2.md b/sunrise_special/6/Gestruktureerd programmeren in ML deel 2.md new file mode 100644 index 0000000..806e3e7 --- /dev/null +++ b/sunrise_special/6/Gestruktureerd programmeren in ML deel 2.md @@ -0,0 +1,205 @@ + G E S T R U C T U R E E R D + + P R O G R A M M E R E N I N M L ( 2 ) + + + Na de inleiding van Alex van de vorige keer gaan we nu echt + beginnen. De methode die ik ga uitleggen in dit deel en de + volgende delen heet stapsgewijze verfijning of top-down. Ik + zal het hier toespitsen op ML, in de Modula-2 cursus komt in + principe hetzelfde verhaal, alleen dan voor Modula-2. + + + S T A P S G E W I J Z E V E R F I J N I N G + + Het principe is zeer simpel. Je wilt een probleem oplossen. + Je schrijft het probleem eerst in pseudo-code op, meestal + zal dat een soort krom Nederlands zijn. Je splits het + probleem hierbij op in ongeveer drie of vier deelproblemen. + + Vervolgens leg je voor ieder van de deelproblemen stap voor + stap nader uit wat er wordt bedoeld. Je gaat elk + deelprobleem weer op dezelfde manier behandelen, totdat je + op een gegeven moment op zo'n laag niveau bent aangeland dat + je het zonder problemen in ML kunt zetten. Het verfijnen + gaat net zo lang door totdat een compleet ML programma is + ontstaan. + + Het voordeel van deze methode is dat je maar een klein + gedeelte van het totale probleem tegelijk hoeft te overzien + in ML, het zal je op dat moment een zorg zijn hoe de rest is + geprogrammeerd. Hierdoor blijft het overzichtelijk. + + In Modula-2 heb je procedures en parameters om dit allemaal + in goede banen te lijden, in ML zul je dit allemaal zelf + moeten doen. Vooral de parameters (lees: registers) zijn + nogal eens een probleem, je moet goed opletten welke + registers je moet bewaren en welke je rustig kunt + veranderen. + + Het is belangrijk dat je er bij het schrijven van een + routine vanuit gaat dat de routines die je daarin aanroept + al werken. Dat is dus niet zo! Je werkt topdown, van boven + naar beneden dus en je schrijft dus eerst de hoofdroutine, + dan de routines die door de hoofdroutines worden + aangeroepen, dan de routines die weer door die routines + worden aangeroepen, etc. + + Een probleem daarbij is dat je vantevoren vaststelt via + welke registers de in- en uitvoer van een routine op een + lager niveau gaat, en het kan gebeuren dat bij het schrijven + van die routine blijkt dat je beter andere registers had + kunnen kiezen. Hier is weinig aan te doen, maar door + ervaring zul je dit soort fouten steeds minder maken. + + + V O O R B E E L D + + Om te laten zien wat ik bedoel zal ik het eerste gedeelte + van de hoofdroutine van een willekeurig spel bespreken. Ik + zal hier nog niet tot het laagste niveau afdalen, dat komt + later. + + Stel we hebben een spel met een speler en vijanden, als de + speler tegen een vijand aanloopt moet hij ermee vechten. Het + scherm scrollt niet maar werkt met 'flipscreens' (als je het + scherm uitloopt komt het volgende scherm). + + De eerste aanzet voor een hoofdlus: + + Beweeg vijanden + Beweeg speler + Ga zonodig naar ander scherm + Zet de vijanden en speler op het scherm + Kijk of de speler ��n van de vijanden raakt + Herhaal + + Dit is vrij eenvoudig in ML om te zetten: + + Hoofdlus: CALL MoveEnemies + CALL MovePlayer + CALL OtherScreen + CALL PutSprites + CALL CheckHit + JR Hoofdlus + + Dit is erg overzichtelijk en het is zeer eenvoudig om nog + iets extra's toe te voegen. Als er bijvoorbeeld een + tijdslimiet is dan wordt het bijvoorbeeld: + + Hoofdlus: CALL MoveEnemies + CALL MovePlayer + CALL OtherScreen + CALL PutSprites + CALL CheckHit + CALL CheckTimeLimit + JR NC,Hoofdlus + CALL OutOfTime + + Waarbij de routine CheckTimeLimit een carry retourneert + indien de tijd is verstreken en OutOfTime een melding op het + scherm zet dat de tijd op is. Het is tijd voor de volgende + stap in het verfijningsproces, de routine MoveEnemies. Het + is misschien erg voor de hand liggend maar de eerste aanzet + daarvoor is: + + FOR i = 1 TO Aantal vijanden + Beweeg vijand nummer i + NEXT + + Soms is het handig om wat BASIC (of bijvoorbeeld Modula-2) + te gebruiken in de pseudo code, dat is korter en + duidelijker. Dit is natuurlijk zeer simpel in ML te + programmeren: + + MoveEnemies: LD A,(AantalEnemies) + LD B,A + MoveEnemies_Lus: CALL MoveEnemy + DJNZ MoveEnemies_Lus + RET + + Het ontwerp van MoveEnemy ziet er bijvoorbeeld zo uit: + + Bepaal welke richting de vijand op moet + Kijk of dat mogelijk is (i.v.m. obstakels) + Zo ja, pas dan de co�rdinaten aan in de gewenste + richting + + Ook dit is weer eenvoudig in ML om te zetten: + + ; MoveEnemy + ; Beweeg een vijand + ; In : B = nummer van vijand + ; Uit: B is ongewijzigd + + MoveEnemy: CALL WhichDirection + CALL CheckIfPossible + RET C + CALL ChangeCoors + RET + + Waarbij de headers van de routines WhichDirection, + CheckIfPossible en ChangeCoors er zo uitzien: + + ; WhichDirection + ; Bepaal welke richting een vijand op moet gaan + ; In : B = nummer van vijand + ; Uit: A = richting + ; B is ongewijzigd + + ; CheckIfPossible + ; Bepaal of het mogelijk is voor monster B om in richting A + ; te bewegen + ; In : A = richting, B = monster + ; Uit: carry = niet mogelijk/no carry = wel mogelijk + ; A en B zijn ongewijzigd + + ; ChangeCoors + ; Monster B beweegt in richting A + ; In : A = richting, B = monster + ; Uit: coordinaten zijn gewijzigd + ; B is ongewijzigd + + En zo kun je dus verder gaan totdat je bij de echte code + uitkomt, ChangeCoors is daar bijvoorbeeld al een geschikte + kandidaat voor. + + + L A Y O U T + + De gebruikte layout is zeer belangrijk voor de leesbaarheid + van je programma. Zelf programmeer ik 'case sensitive', ik + zet alle Z80-instructies in hoofdletters en labels beginnen + met een hoofdletter en zijn voor de rest kleine letters + behalve als er een nieuw woord begint in een label. Ik werk + met een labellengte van 16 tekens zodat ik fatsoenlijke + namen voor routines kan gebruiken en ook nog ruimte heb om + er dingen als "_Lus" achter te plakken. + + De TABs zijn als volgt ingesteld: + + 1 label + 19 instructie + 25 operand + 43 commentaar + + Dus bijvoorbeeld: + + Schermopbouw_Lus: LD A,AantalKolommen ; commentaar + + Het lijkt hier alsof de ruimte voor commentaar erg klein is + maar normaal gesproken heb je natuurlijk 80 kolommen (hier + 60). Je kunt zelf je eigen layout kiezen, als je hem maar + consequent volhoudt en er geen puinhoop van maakt. Ik heb + deze layout bij WR gebruikt en dat is erg goed bevallen. + + Het voordeel van lange labels blijkt al snel als je gaat + bedenken wat het label Schermopbouw_Lus in WB-ASS2 zou + worden: SCOB_L of zoiets. Niet echt leesbaar dus, zeker niet + als het alweer een paar weken geleden is dat je voor het + laatst naar die source gekeken hebt. + + De basisprincipes zijn nu hopelijk duidelijk, de volgende + keer zal ik hier verder op doorgaan. + + Stefan Boer diff --git a/sunrise_special/6/HDSpeed.md b/sunrise_special/6/HDSpeed.md new file mode 100644 index 0000000..a176709 --- /dev/null +++ b/sunrise_special/6/HDSpeed.md @@ -0,0 +1,49 @@ + H D S P E E D + + + HDSPEED heb ik gemaakt om de snelheid van een drive te + meten. Bij DOSSCAN, die gebruikt werd door Gouda, moet je + zelf de tijd bijhouden, en da's dus ietwat onnauwkeurig. Bij + mijn programma wordt de tijd gewoon uit de clockchip + gehaald. + + HDSPEED.COM werkt gewoon zoals je verwacht, alleen kun je de + drive niet opgeven. Er wordt gewoon telkens de default drive + genomen. + + + E N K E L E R E S U L T A T E N + + De volgende resultaten zijn op een turbo R met LUNA (zie de + tekst op deze Special) gemeten: + + MK interface: 46 kB/s + Gewone drive: 17 kB/s + RAMdisk : 500 kB/s + + Deze zonder LUNA: + + MK interface: 35 kB/s + Gewone drive: 12 kB/s + RAMdisk : 150 kB/s + + Het verschil dat LUNA maakt komt gewoon doordat hij de R800 + aanschakelt bij disk-access. Als de cache gebruikt wordt + komt het bij alle drives (behalve de RAMdisk) uit op zo'n + 200 kB/s. + + + V O L G E N D E V E R S I E S + + Ik wil nog een aantal dingen uitbreiden. Maar het + belangrijkste ervan is het gebruiken van de testmode van de + clock-chip. Dan kan het meten van de tijd supernauwkeurig + gebeuren. Zie voor details het artikel over de clock-chip op + deze Special. + + Kasper Souren + + + NB: DOSSCAN.PMA heb ik ook maar erbij gezet. Maar deze geeft + de transfer rate niet altijd. Ik weet niet waar dat aan + ligt. diff --git a/sunrise_special/6/Luna.md b/sunrise_special/6/Luna.md new file mode 100644 index 0000000..b9729ff --- /dev/null +++ b/sunrise_special/6/Luna.md @@ -0,0 +1,191 @@ + L U N A + + + B E T E R E D I S K - C A C H E + + Op Sunrise Magazine #11 werd DOS2CASH besproken. Nu is er + alweer een veel beter programma om te cachen! Het heet Luna + - en heeft volgens mij niet veel met een lunapark te maken - + en is dit jaar nog gemaakt. Het is dus een vrij nieuw + programma. + + Het is net als DOS2CASH afkomstig uit Japan, en het komt van + een reeks diskettes met allerlei PD programma's uit Japanse + BBS'en. + + + H A R D D I S K ! + + Luna kan ook de harddisk cachen, en het helpt ook nog! Luna + vertraagt wel een beetje bij de eerste keer laden, maar als + je iets uit het cache-geheugen laadt, gaat het echt + razendsnel. + + Voor turbo R gebruikers is er het goede nieuws dat het + programma ook een soort R800-drive bevat. Je kunt nu per + drive instellen of er gelezen en geschreven moet worden met + de R800 mode aan. + + + G E H E U G E N N E M E N + + Met de volgende functies kun je aangeven hoeveel geheugen + LUNA.COM moet innemen. + + nnnn : Gewoon een getal van 80 tot 4096. Dit is de ruimte, + in kB's, die Luna gebruikt als cache-geheugen. + + Snnn : Hier geeft het getal niet het aantal kB dat Luna + gebruikt, maar het aantal mapper segmenten. Elk + segment is 16 kB groot. + + Ennnn: Met E wordt de vrije ruimte aangeduid. + + ESnnn: Hier is het getal natuurlijk het aantal vrije mapper + segmenten. + + De minimale hoeveelheid geheugen die Luna nodig heeft is + overigens 80 kB, oftewel 5 segmenten. + + + C H E C K T I M E + + Met de letter T kun je een bepaalde tijd opgeven. Deze tijd + staat voor een aantal interrupts. Als je er nu binnen deze + tijd al een disk-aanroep is geweest, controleert Luna niet + of dezelfde disk nog in de drive zit. Als je computer op 50 + Hz staat is 50 eenheden uiteraard 1 seconde. + + Bijv. LUNA T300 om bij een computer op 60 Hz pas na (300/60 + =) 5 seconde weer te checken op de bootsector, en bij 50 Hz + (300/50 =) 6 seconde te wachten. + + + F L A S H E N + + Bij de optie F heeft de help-optie (/H of /?) van Luna het + over flash time. Wat dit precies inhoudt is me nog + onduidelijk. Ik vermoed dat het gewoon het laten knipperen + van een aantal LED's bij het weer opnieuw herkennen van een + disk. In ieder geval geef je met Fnnnnn de tijdsduur van het + knipperen aan. + + + L E D S S P E C I F I C E R E N + + Bij de opties die hieronder vermeld staan kun je de volgende + letters gebruiken: + + C: CAPS + K: KANA; dit is alleen bij Japanse computers van toepassing + P: PAUSE: alleen bij MSX turbo R + T: turbo: idem + + Deze staan voor de bijbehorende LED's, en als de handeling + verricht wordt, worden de LED's aangemaakt als ze aanstaan, + en uitgemaakt als ze uitstaan. Gewoon ge�nverteerd dus. + + Met LC kun je de LED's specificeren die ge�nverteerd worden + bij het cachen. Dus bij alle lees- en schrijfopdrachten + waarbij het cache-geheugen gebruikt wordt. + + LF geeft aan welke LED's worden gebruikt bij het flashen. LA + doet hetzelfde, maar dan bij een zogenaamde all-flash. + Flashen is het laten wisselen van de disk. Wat het precies + inhoudt heb ik wel al gehoord, maar toen heb ik het niet + direct opgeschreven/onthouden. Ik zal wel zorgen dat het op + een volgende Special/Magazine staat. + + + P R O T E C T E D S E C T O R S + + Achter F kun je gewoon de eerste normale sector opgeven, en + dan geldt dat voor alle drives. Het is echter ook mogelijk + om drives te zetten achter F. Dan geldt de sector alleen bij + die bepaalde drives. Uiteraard kun je dus ook meerdere keren + F gebruiken. + + Bijv. LUNA FABC29 als de protected sectors van drives A: t/m + C: van 0 tot en met 28 lopen. + + + P E R D R I V E U I T + + Met A kun je aangeven welke drives geen automatische flash + hebben. Het doel hiervan is - je raadt het al - me niet + compleet onduidelijk. De drives komen gewoon achter de A. + + D is om bij bepaalde drives het cachen uit te zetten. Bij de + HG SCSI interface zou de cache wel eens alleen maar + vertragend kunnen werken, en dan is deze optie natuurlijk + wel handig. (Luna blijft echter handig, want je moet toch af + en toe met gewone disks werken.) + + Bijv. LUNA dACD om drive A:, C: en D: niet te cachen. (Voor + de duidelijkheid gebruik ik hier een kleine D.) + + + R 8 0 0 - D R I V E + + Met de optie R en W kun je aangeven of de R800 moet worden + aangezet bij respectievelijk het lezen (Read) en schrijven + (Write). + + Als je een turbo R hebt, kun je het beste al je drives met + de R800 aan laten lezen. Schrijven gaat soms fout bij gewone + drives, maar harddisk en RAMdisk kunnen het zonder problemen + aan. + + Bijv. LUNA rABCDEFH wABCDH om, zoals in mijn geval, alleen + drive E: en F: niet met R800 aan beschreven te laten worden. + + + O P T I E S + + /U : Upper RAM mode aan. Nu zet LUNA zich zoveel mogelijk in + een andere mapper dan de primaire (da's de interne bij de + turbo R, en bij andere computers de eerste), en in de + hoogste mappersegmenten. + + /P : Stored PCM aan. Op een of andere manier is het dan + mogelijk dat de computer een sample afspeelt na een + diskwissel. + + /S : Seek speed up uit. Met de optie /S kun je iets weer + normaal zetten dat LUNA aanpast aan de diskdrive aansturing + bij de turbo R zodat het sneller gaat. Dit gaat soms fout + bij twee diskdrives, en dan moet je dus de optie /S + gebruiken. + + /F : FAT protect off. Met deze optie kun je het beschermen + van de FAT tegengaan. Zie ook de uitleg bij F. + + /D : Auto flash off. Tja... + + /M : Message off. Zo krijg je geen overzicht van de + instellingen. Met redirection naar NUL krijg je overigens + helemaal niks op het scherm. Dus met NULU >NUL. + + /C : De opties die nu achter LUNA staan, worden in LUNA.COM + bewaard. Als LUNA.COM gePOPCOMd is, wordt dit weer ongedaan + gemaakt door het saven zelf. Hierna moet je dus even opnieuw + POPCOMmen. + + /J : Laat de bewaarde parameters op het scherm zien. Handig + wanneer je maar ��n ding wilt aanpassen. Want bij /C worden + de oude paramters ongedaan gemaakt. + + /R : Haal Luna uit het geheugen. + + /H of /? : Geeft een beknopt overzicht van alle opties van + Luna. + + + L U N A E N M A P + + Helaas pindakaas. Als je Luna in het geheugen hebt, en je + runt MAP, dan blijft de computer hangen bij de volgende + disk-access. Als je MAP dus toch nog nodig hebt, moet je + eerst even LUNA verwijderen met LUNA /R. + + Kasper Souren diff --git a/sunrise_special/6/MSX View.md b/sunrise_special/6/MSX View.md new file mode 100644 index 0000000..c2f9961 --- /dev/null +++ b/sunrise_special/6/MSX View.md @@ -0,0 +1,102 @@ + M S X - V I E W + + + Iedereen kent wel Halos. Het operating system van HAL + laboratories dat er goed uitziet maar slecht werkt en + eigenlijk onwerkbaar is. Mensen die het versienummer wel + eens hebben bekeken weten dat de Halos die idereen heeft + versie 0.0.4 is van de echte Halos die in Japan te koop is. + De uiteindelijke Halos is weer de voorloper van MSX-View. De + twee zijn danook bijna identiek. (MSX-View is voor tR en + werkt onder DOS2, dus met shells e.d.) + + MSX-View is een programma dat het mogelijk maakt om met + windows te werken en nog veel meer. MSX-View zelf bestaat + enkel en alleen uit een kernel die verborgen zit in de + memorymapper. Zijn 300 a 400 functies zijn aan te roepen via + RST 8 DW [functienr]. Gelukkig zijn er ook zgn. applicaties + voor MSX-View zoals VSHELL (een DOS-Shell), ViewTED (een + tekst editor), ViewDRAW (een DTP programma) etc. Daarover + wil ik eigenlijk niet gaan schrijven, en dit is dus bedoeld + voor programmeurs. + + + A A N S T U R E N V A N M S X - V I E W + + Oftewel het zelf schrijven van applicaties en .DA files. + (Overlay programma's die tijdens de uitvoering van een + applicatie kunnen worden ingeladen, denk aan een calculator, + notitieboekje, etc.) Toevallig ben ik ooit eens tegen een + MSX-FAN opgelopen met daarop MSX-View library's voor MSX-C. + Door de informatie die hier in staat is het mogelijk zelf + applicaties te schrijven is zowel C als assembly, wat je + maar wilt. Ik heb mijn eerste applicatie al af. + + Iedere C of ML programmeur moet volgens mij applicaties + kunnen schrijven. Zo moeilijk is het niet. En hoe meer + applicaties hoe meer ondersteuning MSX-View krijgt en dat is + ook belangrijk. + + + W A A R O M N I E T I E T S A N D E R S + + Ik hoor iedereen nu al weer roepen: MSX-View is Japans, daar + heb je niets aan, het is veel te ingewikkeld en te traag en + ik schrijf zelf wel een goed windows programma. Maar neem + maar van mij aan dat dit het beste windows programma is dat + ooit op de MSX zal verschijnen. MSX-View zelf is alleen een + kernel en hoewel er standaard messages inzitten + (bijvoorbeeld copy of quit, maar dan in het Japans) hoef je + die natuurlijk niet te gebruiken. En anders koop je toch + gewoon de MSX-View patch van MGF, dan zijn die standaard + messages ook vertaald. Wees dus niet eigenwijs en gebruik + MSX-View. Het is echt waanzinnig goed. + + + F U N C T I E V O O R B E E L D E N + + Een paar voorbeeldfuncties met uitleg: + + GetEvent - Kijkt welke keuze is gemaakt/toets is + ingedrukt,etc. + FrontWin - Zet het huidige window voor alle andere + windows. + DispAllCntl - Drukt alle controls af (bv. schuif, + switch, checkmark) + OpenMenu - Opent pull-down menu systeem (gedefenieerd + door eigen programma) + InitGraf - Initializeert de MSX-View GrafPack + FillPai - Drukt een stuk cirkel af, gevuld met een + patroon + GetDiskInfo - Haal informatie op over een diskdrive(of + disk die erin zit) + GetSin - Haal een waarde uit de sinus-tabel + FilePack(...) - Laad/Save een (gedeelte van een) file + (Er verschijnt een keuzemenu waar + directories,drives en files kunen worden + doorlopen, een naam kan worden ingegeven + en vervolgens OK of ABORT kan worden + gekozen.) + ErrMessage - Plaats een error-window in het midden van + het scherm met een message, een of + meerdere buttons eronder en evt. en teken + ernaast (disk, uitroepteken...) keert + terug met de gekozen button in A + + MSX-View werkt ook met gestandariseerde dataopslag. De + GetEvent levert het event bijvoorbeeld in een door jou + gekozen eventbuffer. Het systeem is door zijn jarenlange + ontwikkeling geperfectioneerd tot in de kleinste details en + dat blijkt uit alles. + + + Z E L F A P P L I C A T I O N S M A K E N ? + + Als je interesse hebt in hoe dit alles in de praktijk in + zijn werk gaat, of je hebt belangstelling voor de library's + en programma's waarmee dit alles moet worden bewerkstelligd + dan hoef je alleen maar even contact op te nemen met mij via + post, telefoon of echomail, uploads/downloads alleen via + Piramide BBS. + + Jan van Valburg diff --git a/sunrise_special/6/MSX2 Blink besturing.md b/sunrise_special/6/MSX2 Blink besturing.md new file mode 100644 index 0000000..892d913 --- /dev/null +++ b/sunrise_special/6/MSX2 Blink besturing.md @@ -0,0 +1,304 @@ + M S X 2 B L I N K B E S T U R I N G + + + Een van de nieuwe mogelijkheden van de MSX2 video chip is de + zogenaamde BLINK. Voor screen 0 is dit een extra + mogelijkheid om delen van het scherm van een 3e en/of 4e + kleur te voorzien. Ook in andere screen modes is de blink + uitstekend te gebruiken. Maar in dit artikel beperk ik me + tot screen 0 mode 80. + + In de VDP cursus #7 is hier ook al het een en ander + geschreven. In dit artikel zal ik proberen de mogelijkheden, + en vooral het gebruik van de blink te beschrijven, met -in + assembly geschreven- routines. + + + B A S I S A D R E S + + Elke positie op het scherm kan in de blink mode worden + gezet. Voor elke positie is 1 bit gereserveerd. Als deze + hoog is, is de blink geactiveerd. Deze informatie wordt + bewaard in de Blink tabel. Het start adres van deze tabel + wordt gespecifeerd door het zetten van de 8 hoge bits in + register #3 en #10 (A9-A16). De 9 laagste bits zijn altijd + "1" waardoor de tabel altijd om de 512 bytes ligt. Een blink + tabel is 512 bytes lang, dus kunnen er 512*8 posities op het + scherm worden aangezet (1 bit per karakter). + + MSB b7 b6 b5 b4 b3 b2 b1 b0 LSB + r#3 A13 A12 A11 A10 A9 1 1 1 + r#10 0 0 0 0 0 A16 A15 A14 + + Formules: + VRAM adr = r#3 and &hF8 * 64 + r#3 = VRAM adr / 64 and &h00F8 or &h07 + + Hierbij laat ik r#10 gewoon nul, omdat in de praktijk de + blink tabel nooit zo hoog in het VRAM zal worden gezet. + + Stel we willen de Blink tabel laten beginnen op VRAM adres + &h0E00, dan zullen de register als volgt moeten worden gezet: + + r#3 &h3F (&h0E00/64 or 7) + r#10 &h00 + + standaard zijn deze registers gevuld met de volgende + waarden: + r#3 &h27 (VRAM adr: &h0800) + r#10 &h00 + + In Assembly zal een dergelijke berekening voor het basis + adres er als volgt + uitzien: + + ; Set Blink Base address. + ; In: H(L), VRAM adr. L, not necessary. + BLNBAD: XOR A ; Hoogste bits:0 + LD (BLN_BA),A + LD A,H + AND &HFE + LD (BLN_BA+1),A + RLCA + RLCA + AND &HF8 + OR &H07 + DI + OUT (&H99),A + LD A,3 OR &H80 ; r#3 + OUT (&H99),A + EI + RET + BLN_BA DW &H0800 ; (standaard) + + Omdat het adres altijd in stappen van 512 bytes gaan, zullen + de 8 laagste bits in ieder geval "0" zijn. Vandaar dat de + routine begind met het nul maken van de laagste bits. + Het VRAM adres wordt bewaard, zodat deze later is te + gebruiken bij het beschrijven van deze tabel. + + + K L E U R E N T I J D S D U U R + + De kleuren van de blink worden gezet in r#7. Waarbij de + hoogste 4 bits de kleur van de karakters is, en de laatste 4 + bits de kleur van de blink achtergrond. + + MSB b7 b6 b5 b4 b3 b2 b1 b0 LSB + r#7 FC3 FC2 FC1 FC0 BC3 BC2 BC1 BC0 + + N.B. FC0-FC3: Foreground Colour + BC0-BC3: Background Colour + + voorbeeld: + We willen de karakters waar de blink mode aan staat, geel + maken, en de achtergrond daarvan rood. Dan wordt r#7 als + volgt: + r#7, &hA6 (A=geel, 6=rood) + + Voor de tijd dat de blink mode aan/uit staat, moeten we r#12 + gebruiken. De 4 hoogste bits bevatten de tijd dat de kleuren + (r#3) worden geactiveerd, de 4 laagste is de tijd dat de + originele karakter kleuren weer worden geactiveerd. + + MSB b7 b6 b5 b4 b3 b2 b1 b0 LSB + r#12 BC3 BC2 BC1 BC0 CC3 CC2 CC1 CC0 + + N.B. BC0-BC3: Blink Colour + CC0-CC3: Charakter Colour + + De tijd wordt aangegeven in "vertical scans", dus elke 1/50 + (of 1/60) seconde. + + Met deze 4 genoemde registers is de initialisatie van de + blink verklaard. Alles wat we nu nog moeten doen is + daadwerkelijk de scherm posities aan of uit zetten. + + + S C H E R M P O S I T I E + + De posities van de blink worden als volg berekend: + (uitgaand van een width 80 scherm) + + [basis adres] + (Yx10) + (X/8) + + Omdat er per bit wordt gerekend, wordt de X gedeeld door 8 + (8 bits). Omdat er maximaal 80 karakters op een scherm + kunnen, worden er dus 10 bytes gebruikt voor een Y lijn + (80/8). + + Voordat we de blink gaan gebruiken, doen we er goed aan om + eerst de hele blink tabel leeg te maken. Een soortgelijke + routine: + + ; Clear Blink table. + BLNCLR: LD HL,(BLN_BA) ; basis adres + LD C,0 ; laagste 64k. + LD DE,512 ; totaal aantal bytes + XOR A ; vul met nul + JP FILVRM ; een "Vul VRAM" routine + + De "FILVRM" routine in dit voorbeeld heeft de volgende + data nodig: + HL/C, VRAM adres C bepaalt welk VRAM blok (64k.) + DE, lengte + A, vuldata + + Natuurlijk kunt u uw eigen routine ook gebruiken. + + Nu komt eigenlijk het moeilijkste, een routine maken die een + blink positie aan of uit zet. Hierbij moet het VRAM adres, + en het start bit worden berekend. Dit laatste is + noodzakelijk omdat immers per bit wordt gerekend. Ook is het + belangrijk, dat de bits die al aan/uit stonden onveranderd + te laten! + + De volgende routine zal het VRAM start adres berekenen: + + ; Calculate Blink VRAM adr. + ; In: H, pos-X. L, pos-Y + ; Out: HL, VRAM adr. + C_BLAD: LD A,H + RRCA ; X/8 + RRCA + RRCA + AND &HF8 + LD H,A + LD A,L ; Yx10 (Yx2 + Yx8) + RLCA + AND &H3F + LD L,A ; L=Yx2 + RLCA ; Yx4 (+Yx4 = Yx8) + RLCA + ADD A,H ; (Ax8) + (Ax2) + ADD A,L ; + X + LD L,A + LD A,(BLN_BA+1) ; basis adres + LD H,A + LD (BLN_AD),HL ; bewaar VRAM adres + RET + + BLN_AD DW &H0800 + + Deze routine is uiters snel qua berekening, maar heeft 1 + beperking, dat er maar 256 VRAM adressen (2048 posities) + kunnen worden berekent Hierdoor is het start adres bekend, + nu nog het start bit. + + Door gebruik te gaan maken van een vermenig vuldigins + routine, is dit wel mogelijk maar dat gaat dan wel ten koste + van de snelheid. Voor dergelijke rekenroutine verwijs ik u + naar de Z80 REKEN cursus van Alex van der Wal (special #5). + Een blink adres berekening routine gebruik makend van + vermenig vuldiging: + + ; calc Blink VRAM-adres. + ; In: HL, XXYY (blink pos.) + C_BLAD: LD A,H + AND &HF8 + RRCA + RRCA + RRCA ; /8 + PUSH AF + LD A,L ; Y*10 + LD DE,10 + CALL HL=ADE ; Uit: HL= A x DE + POP AF + LD C,A + LD B,0 + ADD HL,BC + LD BC,(BLN_BA) + ADD HL,BC + LD (BLN_AD),HL + RET + + A bevat nu een bit waarmee moet worden gestart. Stel nu dat + we als X positie 5 nemen. Het start bit (in reg. A) zal dan + als volgt zijn: (uitgaand dat X de waarde 0-79 kan hebben) + + A, &b00000100 ; 5e bit van links is hoog. + + Met deze start gegevens kunnen we nu een scherm positie + voorzien van de blink mode. De volgende routine zal een + (aantal) posities aan (kunnen) zetten: + + ; Set blink position ON. + ; In: H, pos-X. L, pos-Y. B, total positions + BLNON: PUSH BC + LD A,H + PUSH AF + CALL C_BLAD ; VRAM adres + POP AF + CALL C_STBT ; start bit + POP BC + LD E,A + BLON.1 LD C,0 ; laagste 64k. + CALL SR_VRM ; Zet VDP in lees mode. + IN A,(&H98) ; Lees oude blink bits. + PUSH AF + CALL SW_VRM ; Zet VDP in schrijf mode. + POP AF + BLON.0 OR E + RRC E ; Schuif bit + JR NC,BLON.2 ; Laagste bit gehad? + OUT (&H98),A ; ja, schrijf Blink + INC HL : volgende 8 posities. + DJNZ BNON.1 + RET + BLON.2 DJNZ BLON.0 + OUT (&H98),A + RET + + De routines "SR_VRM" en "SW_VRM" zorgen er voor dat de VDP + in lees of schrijf mode wordt gezet. Natuurlijk kunt u hier + ook uw eigen routines gebruiken. + De "OR E" instructie zorgt ervoor dat de desbetrefende bits + worden gezet, zodra het laatste bit gedaan is (b0), wordt de + volgende VRAM positie (8 bits) gebruikt. + + Een routine die of een (of meer) blink positie(s) zet: + + ; Reset Blink position. + ; In: H, pos-X. L, pos-Y. B, total pos. + BLNOFF: PUSH BC + LD A,H + PUSH AF + CALL C_BLAD ; VRAM adres + POP AF + CALL C_STBT ; start bit + POP BC + CPL ; draai bits om + LD E,A + BLOF.1 LD C,0 ; laagste 64k. + CALL SR_VRM ; Zet VDP in lees mode. + IN A,(&H98) ; Lees oude blink bits. + PUSH AF + CALL SW_VRM ; Zet VDP in schrijf mode. + POP AF + BLOF.0 AND E ; zet 1 bit uit. + RRC E ; Schuif bit + JR C,BLOF.2 ; Laagste bit gehad? + OUT (&H98),A ; ja, schrijf Blink + INC HL : volgende 8 posities. + DJNZ BNOF.1 + RET + BLOF.2 DJNZ BLOF.0 + OUT (&H98),A + RET + + Deze routine is feitelijk het zelfe als "BLNON", maar nu + wordt de instructie "AND E" gebruikt om de bits uit te + zetten. + Met deze 2 laatst genoemde routines is het natuurlijk heel + makelijk om een routine te maken die een Blok aan of uit + zet, waarbij bijvoorbeeld "B" het aantal X posities is en + "C" het aantal Y posities. Hierbij kan gebruik worden + gemaakt van het VRAM adres wat opgeslagen staat in "BLN_AD". + Nu hoeft het adres, en het start bit maar 1 keer worden + berekend. Het VRAM adres van de volgende Y posities ligt 10 + hoger. + + Met deze routines en uitleg moet het mogelijkzijn om de + Blink voledig te benutten in screen 0. + + R�man van der Meulen diff --git a/sunrise_special/6/Memman TSR Development Kit.md b/sunrise_special/6/Memman TSR Development Kit.md new file mode 100644 index 0000000..cbfa6bb --- /dev/null +++ b/sunrise_special/6/Memman TSR Development Kit.md @@ -0,0 +1,81 @@ + T S R D E V E L O P M E N T K I T + + + Producent : MSX Software Team + Computer : + M S X 2 (80 kB RAM) + Medium : 1 dubbelzijdige diskette + Leverancier: MCCM's lezersservice + + + H E T P A K K E T + + ...bestaat uit een handleiding en een disk. Veel tekst uit + de handleiding zullen de meeste kopers van het pakket al + hebben: documentatie van MemMan calls en het artikel over + interrupts dat al in MCM heeft gestaan. Nieuw zijn echter de + beschrijving van het maken van TSR's volgens de MemMan + standaard - toevallig het belangrijkste - en de sources van + de PB.TSR en PRINT.COM. + + + D I S K + + Op de diskette staat eveneens een groot aantal files die al + in het bezit zijn van potenti�le kopers. Alleen LT.COM, de + linker, en daardoor het belangrijkste stukje bitvolgorde op + deze disk, en de raamwerken voor TSR-listings voor M80 en + GEN80. Ook zijn er nog 2 batchfiles, maar dat mag niet + bijster interessant worden genoemd. + + Wat je op deze disk mist zijn de 2 sources die wel in de + handleiding staan geprint. Misschien is dit gedaan ter + voorkoming van het vrijkomen van versies met hele kleine + aanpassingen. + + + R E L - B E S T A N D E N + + De linker werkt alleen met relocatable files. Files die op + een door de gebruiker of een ander programma dan de + assembler op de juiste plaats te zetten zijn. Beschrijving + van deze REL-files is te vinden op Sunrise Special #1. + + Voor zover ik weet is het alleen met GEN80 en M80 mogelijk + om REL-files aan te maken. Bij M80 is het trouwens alleen + maar mogelijk om REL-files te produceren. WB-ASS2 gebruikers + worden hierdoor uitgesloten, maar dit is niet zo erg: GEN80 + is toch veel beter! + + De linker maakt van die REL-files TSR-files. Deze files zijn + mijns inziens gewoon veredelde REL-files. In zoverre + veredeld dat TsrLoad ze makkelijk in een MemMan segment kan + plaatsen. + + + Z E L F M A K E N + + Zelf een TSR maken is een koud kunstje met dit LinkTsr. In + je source geef je de hook(s) aan die wilt afbuigen en zet je + de code die aan die hook(s) komt te hangen. Je hoeft je + verder dus niet te bekommeren over het vrijmaken van ruimte + in de top van het geheugen en het correct afbuigen van de + hooks. + + Als voorbeeld staan CHGCPU2.TSR en VOLINMET.TSR met source + en uitleg op deze Special. + + + C O N C L U S I E + + Als je dit koopt moet je niet denken dat je iets nieuws in + handen krijgt. Het grote voordeel is dat je nu alles bij + elkaar hebt, in ��n handleiding. Als je makkelijk TSR's wilt + maken, is het zeker aan te raden! Maar ook als je al je + eigen systeem hebt om TSR's te maken is het een aanrader: + het is wel zo leuk voor de gebruikers om een eigen versie �n + een MemMan versie te verspreiden. + + Waarschuwing: alleen voor GEN80- en M80-gebruikers. + + Kasper Souren diff --git a/sunrise_special/6/Memman in theorie en praktijk.md b/sunrise_special/6/Memman in theorie en praktijk.md new file mode 100644 index 0000000..281da30 --- /dev/null +++ b/sunrise_special/6/Memman in theorie en praktijk.md @@ -0,0 +1,241 @@ + M E M M A N + + I N T H E O R I E E N P R A K T I J K + + + I N L E I D I N G + + Onder MSX-DOS 1 laat het geheugenbeheer, met name bij + aanwezigheid van een memory mapper, veel te wensen over. Met + de komst van MSX-DOS 2 is dat sterk verbeterd, daar zitten + immers routines in om een pagina uit de memory mapper op te + roepen en weer vrij te geven. Volgens de deskundigen zit er + echter een bug in deze routines, waardoor eenmaal + opgevraagde pagina's nooit meer vrijgegeven kunnen worden, + tenzij de machine wordt gereset. + + Zo is MEMory MANager geboren. De programmeurs van MST hadden + de behoefte aan een stel goed werkende routines, waarmee het + gehele geheugen benut kan worden. Ze gingen echter verder. + Meerdere memory mappers, externe geheugen modules (16 & 64 + kB) en TSR's. Welnu over dit laatste onderwerp gaat dit + artikel. + + + W A T I S E E N T S R ? + + Gewoonlijk zal een programma na uitvoering niet in het + geheugen achterblijven. Programma's die dat wel doen, worden + aangeduid met de afkorting TSR: Terminate and Stay Resident. + Voorbeelden van dergelijke programma's zijn printerbuffers + en RAMdisks. Maar ook andere toepassingen, zoals een + rekenmachine of een kalender die met een toetscombinatie + opgeroepen kan worden, zijn denkbaar. + + In het verleden zijn TSR's voor de MSX een tamelijk zeldzaam + verschijnsel geweest. Het probleem was namelijk dat het + geheugen dat de TSR gebruikt, ook door andere programma's + gebruikt kan worden. Er zijn in een standaard MSX machine + geen mogelijkheden om een stuk geheugen voor een TSR te + reserveren. Dit probleem wordt door MemMan uit de wereld + geholpen. MemMan beheert het geheugen en zorgt er voor dat + er geen geheugenconflicten optreden. + + Dankzij MemMan is het mogelijk meerdere TSR's tegelijk in + het geheugen te hebben, waarbij elke TSR maximaal 16 kB + groot kan zijn. Op de standaard MSX is het laden van meer + dan ��n TSR al lastig en alleen mogelijk als de TSR niet al + te groot is. Met de invoering MemMan krijgt de MSX betere + TSR mogelijkheden dan de alom gewaardeerde PC. Bovendien + doen ze niet onder voor de 'desktop accesoires' zoals die op + de Macintosh en de Atari ST gebruikt worden. + + Dit hoofdstuk is regelrecht overgenomen uit de handleiding + van MemMan, zoals die is geschreven door het MST. + + + N U D E P R A K T I J K + + Dat klinkt natuurlijk mooi, maar werkt het in de praktijk + ook zo soepel. Ik hoop in de rest van dit artikel een aantal + problemen boven water te halen, waaruit blijkt dat MemMan + heel leuk is, maar nog niet af. Daarentegen wil ik wel + iedereen blijven aanmoedigen om MemMan te blijven (of gaan) + gebruiken, want werken zonder MemMan is helemaal een gruwel. + + + P R O B L E E M 1 + + Een hoop bestaande programma's werken niet samen met MemMan + en profiteren dus niet van het bereikbaar worden van meer + geheugen. Bovendien werken veel programma's niet eens als + MemMan actief is. + + Het eerste gedeelte van het probleem is lastig op te lossen. + Het betekent dat �f het programma herschreven moet worden, + �f er moet een alternatief programma gebruikt worden, dat + wel met MemMan samenwerkt. + + Het tweede gedeelte van het probleem is veel leuker. Ook + hier herken je weer twee probleemgroepen. + + De eerste groep zijn de vastlopers. Als je je bedenkt dat + MemMan binnen de grenzen van de MSX standaard werkt, + betekent dit dat de vastlopende programma's dat dus niet + doen. Programma's die het gehele systeem voor zich opeisen + en denken dat ze ermee mogen doen wat ze willen. Helaas + bestaan ze. + + De tweede groep is het absolute toppunt voor m'n + lachspieren. Het programma geeft kort na het opstarten een + 'Not enough memory' error en het programma stopt. Het + probleem ligt hier in het TPA geheugen. + + Wat is TPA geheugen? Dat is de 64 kB die voor de processor + direct zichtbaar is. De rest van het geheugen is, net als + deze 64 kB, onderverdeeld in blokken van 16 kB. Door nu ��n + van die blokken uit het TPA geheugen te verwisselen met een + blok uit de memory mapper, ziet de processor weer een ander + stukje data of programma. Om dit in goede banen te leiden is + MemMan ontwikkeld. Maar om goed te kunnen functioneren heeft + MemMan permanent een stukje geheugen nodig, zoals ook + MSXDOS(2).SYS en COMMAND(2).COM zich in dit geheugen + bevinden, maar ook de stack e.d.. Wat er nu nog overblijft, + is voor een in te laden programma en z'n te declareren + variabelen. Door MemMan is dat vrije TPA geheugen nu zo'n + 1,5 kB kleiner geworden. Voor sommige programma's genoeg + voor de eerder genoemde error. + + Dit laatste is alleen te verhelpen door het programma + opnieuw te compileren, met een verkleind vrij TPA geheugen. + Hiervoor heb je dan wel de source van het programma nodig en + dat is vaak een probleem. Als het om een commercieel pakket + gaat, is die source simpelweg onbereikbaar voor de + eindgebruiker. Het bedrijf wenst niet meer aan het programma + te sleutelen (veel voorkomend commentaar nu MSX commercieel + niet meer interessant is) en wil alleen voor grof geld de + source verkopen. Als het om een PD of shareware pakket gaat, + zou je de schrijver ervan kunnen benaderen met het eerder + genoemde verzoek. Sommigen zullen er gehoor aan geven + anderen niet. Persoonlijk vind ik dat elke programmeur hier + vooraf rekening mee moet houden en dus standaard met een + verkleind TPA geheugen moet compileren. + + Dit probleem is dus niet de schuld van de programmeurs van + MST. Programma's welke voor het MemMan tijdperk geschreven + zijn, kunnen moeilijk verweten worden dat ze niet met MemMan + samenwerken. Maar de overige moeilijkheden van dit probleem + zijn simpel te wijten aan het niet naleven van de standaard, + of het niet wensen rekening te houden met MemMan. Die + programmeurs welke in deze categorie thuis horen, zijn wat + mij betreft amateurs. + + Nvdr. Er is natuurlijk ook nog een categorie: programma's + waarvoor het samenwerken met MemMan onzin is. Bijv. spellen, + demo's en ook deze Special! Al zou de printerbuffer wel leuk + zijn bij het uitprinten. + + + P R O B L E E M 2 + + TSR's zijn vaak op te roepen d.m.v. een toetscombinatie. In + diverse programma's wordt ook gebruik gemaakt van een + toetscombinatie. Wanneer er een TSR actief is welke dezelfde + toetscombinatie gebruikt als een bepaalde functie uit het + lopende programma, heb je een probleem. Welke van de twee + wint nu het gevecht, het programma of de TSR. Oplossing + hiervoor is simpel. Toetscombinaties zijn voor TSR's. In een + normaal programma is het gebruik van toetscombinaties dus + uit den boze. + + Ook hier geldt hetzelfde als bij probleem 1. Programma's van + voor het MemMan en TSR tijdperk, kunnen dit niet verweten + worden. Maar programma's die ontwikkeld zijn toen MemMan en + TSR's wel reeds bestonden, hadden er rekening mee moeten + houden. De programmeurs van deze programma's zijn dus hier + ego�stisch bezig geweest. + + + P R O B L E E M 3 + + TSR's die elkaar in de haren vliegen, of de combinatie van + programma en TSR die elkaar niet liggen. Oorzaak: de al + eerder genoemde toetscombinaties, maar ook het actieve + SCREEN speelt een rol. Dit laatste punt heb ik lang over + nagedacht, maar ik denk dat hier, in tegenstelling tot de + andere moeilijkheden, een taak is weggelegd voor de + programmeurs van MemMan. + + Sommigen van jullie kennen ongetwijfeld de TSR Micro Music. + Deze TSR zet na een bepaalde toetscombinatie een menu op het + scherm. Welnu de programmeur heeft hier geen rekening + gehouden met het actieve screen en gaat er simpel vanuit dat + SCREEN 0 actief is. Gelukkig is hij niet de enige TSR + programmeur die deze fout maakt en het is dus ook geen + persoonlijke aanval op de programmeur van Micro Music. Deze + TSR wordt alleen als voorbeeld genomen. + + Maar ga eens in de positie van de programmeur staan. Eerst + uitzoeken welk SCREEN actief is, vervolgens kijken welk + gedeelte je daarvan wil gebruiken, dan de aanwezige info + ergens opslaan en de nieuwe info plaatsen. Bij het verlaten + van de TSR, moet dan de omgekeerde weg gevolgd worden. Als + je dan ook nog eens toevallig in een modem programma zit en + het scherm is constant aan verandering onderhevig, dan zijn + de rapen helemaal gaar. + + Het is dus veel eenvoudiger om te zeggen dat zo'n TSR alleen + werkzaam is in SCREEN 0. Sommige programmeurs kunnen dit + zelfs niet eens goed (Micro Music laat bij een actieve jANSI + een paar gekleurde blokjes zien boven in het scherm), maar + dat is een ander verhaal. MST zou hier kunnen helpen. + + Wanneer er in MemMan een routine zit, die voor TSR's een + universele manier aanbiedt voor het plaatsen van een + karakter op een op te geven positie op het scherm, ongeacht + welk SCREEN actief is en de oude informatie van die positie + bewaart, zijn we al een hele stap verder. Nu kan de + programmeur van een TSR simpel tegen MemMan zeggen: ik wil + dit karakter op die positie. Wanneer MemMan dan bijhoudt + welke posities gebruikt worden door de TSR, kan de + programmeur van de TSR voor het verlaten van de TSR deze + posities weer herstellen door aan MemMan de opdracht daartoe + te geven. + + De ideale oplossing voor bijna alle problemen. Veel + programma's wijzigen niets op het scherm, wanneer een TSR + actief is. Voor die gevallen dat zowel een programma als een + TSR actief zijn, die beiden het scherm geheel of + gedeeltelijk wijzigen, wordt het praktisch onmogelijk om dit + af te vangen. Die programma's die intensief met MemMan + samenwerken, zouden aan MemMan de door de TSR gebruikte + posities kunnen opvragen en deze dan niet gebruiken, maar + dat kan soms onoplosbare problemen met zich mee brengen. + Denk hierbij alleen maar aan de pulldown menu's e.d.. + + Dus de hier voorgestelde uitbreiding van MemMan is niet + alles dekkend, maar is een hele grote stap in de goede + richting. + + + C O N C L U S I E + + Wat is het leven met MemMan en speciaal hiervoor ontwikkelde + programma's toch een genot. Helaas laten diverse + programmeurs nog wel eens een steekje vallen. Wanneer ze de + inhoud van dit artikel nu eens als wet gaan beschouwen en + wanneer MST de voorgestelde uitbreiding van MemMan nu eens + bewerkstelligt, zijn we bijna waar we zijn moeten: + + Een systeem wat op een bijna optimale manier gebruik + maakt van alle mogelijkheden die het systeem bied. + + Tot slot nog ��n extra opmerking voor de programmeurs. Wees + nu eens niet zo eigenwijs door er van uit te gaan dat de + aangesloten diskdrives A: en B: heten, maar vraag dit gewoon + aan het systeem. Harddisk gebruikers hebben A: en B: vaak in + gebruik als een partitie van de harddisk en de diskdrives + heten dan (in mijn geval) F: en G:. Maar het gebruik van + vele kopieerprogramma's is hierdoor niet meer mogelijk. + + Henk Hoogvliet diff --git a/sunrise_special/6/Memory Mapper.md b/sunrise_special/6/Memory Mapper.md new file mode 100644 index 0000000..1ac0b49 --- /dev/null +++ b/sunrise_special/6/Memory Mapper.md @@ -0,0 +1,272 @@ + M E M O R Y M A P P E R + + + De Z80 kan maar 64 kB geheugen tegelijk adresseren. Om toch + meer dan 64 kB RAM te kunnen gebruiken is de memory mapper + bedacht. De memory mapper behoort niet tot de MSX2- + standaard, en daarom heeft de MSX2 geen standaard + aanstuurroutines voor de memorymapper. + + Vanaf MSX2+ behoort de mapper wel tot de standaard en daarom + zitten er in DOS2 (dat ongeveer gelijktijdig met MSX2+ werd + gelanceerd) wel mapperroutines. + + Veel software die de mapper gebruikt werkt niet onder DOS2, + dat komt door een verkeerd gebruik van de mapper. In dit + artikel zal ik uitleggen hoe de mapper werkt, en hoe je hem + zo kunt aansturen dat het zowel onder DOS1 als onder DOS2 + probleemloos werkt. + + + W E R K I N G + + Het geheugen in een mapper wordt opgedeeld in blokken van 16 + kB, die mapperpages of mappersegmenten worden genoemd. + Aangezien het woord page verwarrend is zal ik hier verder + het woord segment aanhouden. + + Deze segmenten worden oplopend genummerd, te beginnen bij 0. + Een mapper van 256 kB heeft 16 segmenten die genummerd zijn + van 0 tot en met 15. + + De 64 kB adresbereik wordt opgedeeld in vier pages van 16 kB + elk. Op elke page kan een memory mapper worden geschakeld + door gebruik te maken van de routine ENASLT op adres &H24. + Vervolgens kan een segment worden geselecteerd door de + juiste waarde naar de corresponderende out-poort te sturen. + Een overzicht: + + page 0 #0000-#3FFF mapperpoort #FC + page 1 #4000-#7FFF mapperpoort #FD + page 2 #8000-#BFFF mapperpoort #FE + page 3 #C000-#FFFF mapperpoort #FF + + Zo kun je bijvoorbeeld segment 7 selecteren op adres #8000 + met de volgende instructies: + + LD A,7 + OUT (#FE),A + + Het is op zich heel eenvoudig om met verschillende mappers + te werken, gewoon met ENASLT het slot van de gewenste mapper + selecteren op de gewenste page. + + Je mag mapperpoort #FF niet veranderen omdat zich daar het + systeemgebied bevindt. Dit zal altijd segment 0 zijn van de + mapper waarmee de computer opstart. Dit zal bij een MSX2 of + MSX2+ de grootste mapper zijn en bij de turbo R de interne + mapper. Dit omdat de interne mapper van de turbo R sneller + is dan een externe mapper. De communicatie van de R800 met + de cartridgesloten gaat namelijk in een langzamere snelheid. + + Bij het opstarten worden de volgende segmenten geselecteerd: + + page 0 mapperpoort #FC segment 3 + page 1 mapperpoort #FD segment 2 + page 2 mapperpoort #FE segment 1 + page 3 mapperpoort #FF segment 0 + + Wat mij betreft mag je hiervan uitgaan omdat alle bekende + MSX computers het zo doen. Officieel ligt echter alleen vast + dat het systeemgebied zich in segment 0 begint. + + + W R I T E O N L Y ! + + De mapperpoorten zijn officieel write only, wat uiteraard + betekent dat je ze alleen mag beschrijven en dat lezen geen + zin heeft. Toch gaat het lezen meestal goed en het wordt in + programma's die voor DOS1 zijn geschreven dan ook heel veel + gedaan. + + Hierdoor ontstaan twee problemen: + + 1) de software werkt niet meer onder DOS2 + 2) de software werkt niet goed op een MSX2+ of turbo R met + een externe mapper die groter is dan 512 kB + + Ik zal deze problemen hieronder bespreken. + + + D O S 2 + + Ze weten bij ASCII natuurlijk heel goed dat de mapperpoorten + niet mogen worden gelezen en dus wordt dezelfde methode + gehanteerd als voor het 'lezen' van VDP-registers in BASIC, + telkens als er een waarde naar een mapperpoort wordt + gestuurd wordt deze waarde op een vast adres bewaard. De + routine die 'leest' welk segment er voor een bepaalde page + is geselecteerd leest dus gewoon dat RAM adres uit! + + Deze adressen liggen vast en zijn: + + page 0 mapperpoort #FC #F2C7 + page 1 mapperpoort #FD #F2C8 + page 2 mapperpoort #FE #F2C9 + page 3 mapperpoort #FF #F2CA + + Stel je wilt iets laden in segment 7. Je doet dus OUT + (#FE),7 en je roept een BDOS routine aan. Nu komt DOS2 in + actie. Die zet voor de zekerheid de mapper nog even "goed", + hij doet daarvoor LD A,(#F2C9) en OUT (#FE),A. De data komt + dus in een ander segment terecht dan de bedoeling was! + + Dit is de reden waarom programma's die de mapper + rechtstreeks aansturen niet werken onder MSX-DOS 2. De + oplossing voor dit probleem heet MAP. Dit programmaatje werd + gemaakt door Henrik Gilvad uit Denemarken. Het is eigenlijk + heel simpel, hij zoekt gewoon in de DOS2 routines naar de + instructie LD A,(#F2C9) en hij maakt daar IN A,(#FE) van. + Hetzelfde gebeurt met #F2CA en #F2C8, met MAP2, een + uitgebreidere versie, wordt ook #F2C7 'gepatcht'. + + Dit is een paardemiddel dat alleen gebruikt mag worden om te + proberen bestaande software toch onder DOS2 te laten lopen, + de mapperpoorten worden nu immers toch weer gelezen! + + Dat dat niet alleen in de theorie niet mag maar ook niet in + de praktijk blijkt uit het volgende probleem. + + + E X T E R N E M A P P E R + + Bij een externe mapper gaat het lezen van de mapperpoorten + op de Japanse MSX2+ en MSX turbo R computers niet goed! De 3 + hoogste bits zijn namelijk altijd "1"! Dit is de reden + waarom Digital KC in de advertentie voor zijn megamappers + zegt dat ze niet goed werken op MSX2+ en MSX turbo R. + + Omdat het alleen de bovenste 3 bits zijn gaat het bij een + mapper tot 512 kB wel goed, maar dit praktijkgeval bewijst + dat je de mapperpoorten dus echt niet mag lezen! + + + D E O P L O S S I N G + + Op Sunrise Magazine #12 schreef ik nog dat MAP de oplossing + was, maar na een brief van Henrik Gilvad weet ik wel beter. + De enige goede oplossing is om net als DOS2 de waardes die + je naar de mapperpoorten schrijft te bewaren zodat je ze + niet hoeft te lezen. Als je dat onder DOS2 op dezelfde + adressen doet als waar DOS2 dat doet, dan is het meteen + compatible met DOS2 en zal je programma daaronder werken. + Onder DOS1 kun je die adressen beter niet gebruiken omdat ze + zich bevinden in het systeemgebied van de BDOS. Onder DOS1 + gebruik je dus andere adressen dan onder DOS2 om de waardes + op te slaan. + + Onderstaande source bevat routines ReadFE, WriteFE, ReadFC, + etc. Gebruik deze routines voortaan in plaats van OUT + (#FE),A respectievelijk IN A,(#FE). Het is slechts een klein + beetje langzamer en de voordelen zijn duidelijk: het werkt + onder alle omstandigheden op alle computers! + + + ; MAPPER.GEN + ; Standaard mapperroutines + ; Werken onder DOS1 & DOS2 + ; Compatible met DOS2 + ; Voor eerste gebruik InitMapRouts aanroepen + ; Niet rechtstreeks de mapper aansturen, alles + ; via deze routines doen!!! + + ; Door Stefan Boer + ; Sunrise Special #6 + ; (c) Stichting Sunrise 1994 + + ; Init mapper routines + ; Aanroepen voor gebruik van Read/Write routines! + + InitMapRouts: LD A,(#F313) + AND A + RET Z ; DOS1 + + LD HL,#F2C7 ; DOS2 + LD (ReadFC+1),HL + LD (WriteFC+1),HL + + INC HL + LD (ReadFD+1),HL + LD (WriteFD+1),HL + + INC HL + LD (ReadFE+1),HL + LD (WriteFE+1),HL + + INC HL + LD (ReadFF+1),HL + RET + + ; ruimte voor opslag onder DOS1 + + StoreFF: DB 0 + StoreFE: DB 1 + StoreFD: DB 2 + StoreFC: DB 3 + + + ; Read + ; In : - + ; Uit: A = segmentnummer + + ReadFC: LD A,(StoreFC) + RET + + ReadFD: LD A,(StoreFD) + RET + + ReadFE: LD A,(StoreFE) + RET + + ReadFF: LD A,(StoreFF) + RET + + ; Write + ; In : A = segmentnummer + ; Uit: - + ; Er is net als bij DOS2 geen WriteFF want die mag je + ; niet veranderen! + + WriteFC: LD (StoreFC),A + OUT (#FC),A + RET + + WriteFD: LD (StoreFD),A + OUT (#FD),A + RET + + WriteFE: LD (StoreFE),A + OUT (#FE),A + RET + + + Vergeet niet eerst even InitMapRouts aan te roepen, die + zorgt ervoor dat onder DOS2 de gebruikte adressen worden + gewijzigd in de adressen die DOS2 zelf ook gebruikt. Let er + verder op dat de mapper nergens in je programma meer + rechtstreeks wordt aangestuurd, ook niet bijvoorbeeld door + de MoonBlaster replayer. Ik zal nog aan Remco vragen of hij + een nieuwe versie van de replayer released waarin deze + mapperroutines zijn ingebouwd, maar je kunt dit ook + eenvoudig zelf aanpassen. + + + T E N S L O T T E + + Wees nu niet eigenwijs en gebruik deze routines gewoon, ook + als je zelf geen DOS2 hebt. Steeds meer MSX'ers hebben een + harddisk en vaak zal het doorslaggevend zijn bij de + beslissing om je produkt al dan niet te kopen of het op + harddisk kan worden ge�nstalleerd. E�n van de voorwaarden + daarvoor is dat het onder DOS2 werkt. Bovendien zal je + programma op een MSX2+ of turbo R met externe mapper van 1 + MB of meer niet werken als je dat geheugen ook daadwerkelijk + gaat gebruiken. + + Als je in het systeemgebied van DOS2 gaat rondneuzen zul je + overigens zien dat DOS2 exact dezelfde routines gebruikt om + de mapper aan te sturen! Je kunt deze routines echter niet + handig gebruiken omdat ze niet op een vast adres staan. Je + kunt MAPPER.GEN op de disk vinden. + + Stefan Boer diff --git a/sunrise_special/6/Modula2.md b/sunrise_special/6/Modula2.md new file mode 100644 index 0000000..3f38433 --- /dev/null +++ b/sunrise_special/6/Modula2.md @@ -0,0 +1,85 @@ + M O D U L A - 2 + + + G E R E S E R V E E R D E W O O R D E N + + Modula-2 heeft 40 gereserveerde woorden. Al deze woorden + zijn in hoofdletters. + + AND ELSIF LOOP REPEAT + ARRAY END MOD RETURN + BEGIN EXIT MODULE SET + BY EXPORT NOT THEN + CASE FOR OF TO + CONST FROM OR TYPE + DEFINITION IF POINTER UNTIL + DIV IMPLEMENTATION PROCEDURE VAR + DO IMPORT QUALIFIED WHILE + ELSE IN RECORD WITH + + + S P E C I A L E S Y M B O L E N + + Modula-2 kent de volgende speciale symbolen: + + + optellen + - aftrekken + * vermenigvuldigen + / delen + := assignment (toekenning) + & hetzelfde als AND + = gelijkheid + # ongelijkheid + <> ongelijkheid + < kleiner dan + > groter dan + <= kleiner of gelijk aan + >= groter of gelijk aan + () haakjes + [] array-haken + {} set-haken + (* *) commentaar + ^ pointer + .. tot en met + ,.;:~| leestekens + + + S T A N D A A R D I D E N T I F I E R S + + Modula-2 kent de volgende standaard identifiers, ook deze + worden allemaal in hoofdletters geschreven. + + ABS functie absolute waarde + BITSET settype (set = verzameling) + BOOLEAN waar/niet waar type + CAP functie maak hoofdletter van kleine letter + CARDINAL 0, 1, 2, 3, 4, ... type + CHAR character type + CHR functie geeft CHAR met bepaalde ASCII + DEC verlaag + DISPOSE dealloceer geheugen + EXCL verwijder element uit set + FALSE niet waar + FLOAT omzetten CARDINAL naar REAL + HALT be�indig executie van programma + HIGH hoogste indexwaarde van open-array parameter + INC verhoog + INCL voeg element aan set toe + INTEGER ..., -3, -2, -1, 0, 1, 2, ... type + MAX maximum waarde van een opsomtype + MIN minimum waarde van een opsomtype + NEW alloceer geheugen + NIL nulpointer + ODD BOOLEAN functie oneven + ORD rangnummer van een waarde van een opsomtype + REAL floating point type + TRUE waar + TRUNC omzetten REAL naar CARDINAL + VAL geef zoveelste waarde van een opsomtype + + + Alle hier genoemde woorden, symbolen en identifiers zullen + uiteraard nog in de cursus Modula-2 aan bod komen. Dit is + slechts een overzicht met korte beschrijvingen. + + Stefan Boer diff --git a/sunrise_special/6/SCC geluid via stereo pak.md b/sunrise_special/6/SCC geluid via stereo pak.md new file mode 100644 index 0000000..a7583ef --- /dev/null +++ b/sunrise_special/6/SCC geluid via stereo pak.md @@ -0,0 +1,28 @@ + S C C G E L U I D V I A S T E R E O P A K + + + Op een vorige Special stond een tekst over de STEREO SCC, om + het geluid (SCC-PSG) gescheiden weer te geven. Hiervoor + moest u een kleine ingreep doen in uw SCC-cartridge. In deze + tekst wordt uitgelegd hoe u het SCC- en het PSG-signaal door + uw versterker kunt weergeven d.m.v. de stereo FM-PAK! + + Plaats in een van de cartridgesloten uw SCC-cartridge en in + de andere uw stereo FM-PAK. Sluit nu de FM-PAK aan met de 2 + bijgeleverde kabels. Hoe dit moet staat in de handleiding + vermeld. + + Laad nu een SCC-demo of start bijvoorbeeld Solid Snake of + SD-Snatcher op. U zult merken dat het SCC geluid nu prima en + helder door uw stereo-installatie wordt weergegeven. Het + geluid wordt uiteraard nu ook door uw monitor afgespeeld. + Bezitters van alleen een monitor (bij hen ontbreekt dus een + stereo-installatie of er zit geen AUX-ingang op), hoeven + uiteraard deze aansluiting niet te maken. + + Hopelijk kunt u op deze manier beter en mooier van uw SCC + geluid genieten! Zeker als u SD-Snatcher speelt met de BASS + voluit. De ontploffingen van de vijanden klinken dan pas + echt "ECHT"! Succes! + + Haiko de Boer diff --git a/sunrise_special/6/Sprites in de praktijk.md b/sunrise_special/6/Sprites in de praktijk.md new file mode 100644 index 0000000..845bdcb --- /dev/null +++ b/sunrise_special/6/Sprites in de praktijk.md @@ -0,0 +1,156 @@ + S P R I T E S I N D E P R A K T I J K ( 2 ) + + + In de vorige keer heb ik het gehad over het initialiseren + van de sprites en het daad werkelijk plaatsen van een + sprite. In deze aflevering wil ik het sprite verhaal + afsluiten met de kleurcodes voor sprite mode 2 (MSX2 en + hoger) en de sprite botsing detectie (beide modes). + + + S P R I T E K L E U R E N I N M O D E 2 + + In mode 1 wordt het vierde byte in de atribute van een layer + gebruikt om de kleur van een sprite layer te definieren. + Daardoor is er slechts 1 kleur in een sprite mogelijk. De + tweede sprite mode lost dit anders op door hier een aparte + kleur tabel te gebruiken. Hierdoor is het mogelijk om elke Y + lijn van een sprite layer een andere kleur te geven. Door + somige bits te zetten, zijn zelfs 3 kleuren op 1 lijn + mogelijk. Door dat er een kleur tabel wordt gebruikt wordt + het vierde byte in de atribute tabel verwaarloosd. Let op + dat deze byte nog wel aanwezig is, waardoor een sprite layer + atribute nog steed 4 bytes gebruikt. + + Het basis adres van de kleur tabel wordt opgegeven in r#5 en + r#11 zoals in deel in is beschreven. Als deze registers + worden beschreven wordt automatisch het adres van de + atribute tabel gelijk aan de kleur tabel + 512 (&h0200). + + Voor iedere layer zijn 16 bytes gereserveerd voor de kleur. + Ook als er gebruik wordt gemaakt van 8x8 sprites! Als er + 16x16 sprites vergroot worden gebruikt, worden er 2 Y lijnen + met de zelfde kleur gevuld. Een dergelijke kleuren tabel is + dus: 16 x 32 = 512 bytes lang. + + + E X T R A C O D E S + + Samen met de kleur waarden kunnen er ook nog andere bits + worden gezet, die speciale effecten aan de sprite layer + geven. Een kleur byte bevat het volgende: + + MSB b7 b6 b5 b4 b3 b2 b1 b0 LSB + EC CC IC 0 - Kleur code - + + EC: Heeft de zelfde functie als het EC bit in de + atribute tabel van sprite mode 1. Als deze + "1" is wordt de sprite lijn 32 pixels naar + links geschoven. (zie verdere uitleg, deel + 1) + CC: Het zogenaamde prioriteit bit. Als dit "1" + is krijgt de sprite lijn de zelfde + prioriteit als de voorligende sprite. + Hierbij worden de kleuren van beide sprite + ge 'OR'ed. Dit zorgt echter niet voor een + sprite botsing. + IC: Als deze "1" is, wordt een sprite botsing + genegeerd. + + Van elke Y lijn van een sprite kan er een andere kleur en + code worden opgegeven. + + voorbeeld van het prioriteit bit: + (met prioriteit wordt bedoeld dat een layer met een lager + nummer voor een layer met een hoger nummer wordt geplaatst) + + Als de kleur van sprite layer 0 (hoogste prioriteit) kleur 8 + is, en van sprite layer 1 kleur 4. Bij sprite layer 1 wordt + het CC bit gezet. Hierdoor krijgt layer 1 de zelfde + prioriteit als layer 0. De kleuren worden nu ge'OR'ed + waardoor er kleur 12 ontstaat waar de patroon bits "1" zijn. + Hierdoor heeft deze sprite lijn dus 3 kleuren namelijk de + kleuren 4, 8 en 12. + Het start adres van de kleuren tabel: (basic adr: &h7400) + layer 0: &h7400 (CC=0), kleur 4 + layer 1: &h7410 (CC=1), kleur 12 + + + S P R I T E C O N F L I C T + + Hiermee wordt het 'botsen' van sprites bedoeld. In mode 1 + kan alleen worden nagegaan of er een sprite conflict is + opgetreden, terijl in mode 2 ook nog de X en Y coordinaten + van de botsen kan worden opgevraagd. + + Een conflict onstaat als twee sprites elkaar raken. Hierbij + wordt wel gekeken of beide patroon bits van de sprite "1" + zijn en de kleur hiervan niet transparant is. Dus als beide + sprites ook werkelijk geconstrueerd zijn. Het volgende + voorbeeld maakt dit duidelijker: + + sprite 1: XXXX---- sprite 2: //////// + XXXX---- //////// + (8 x 8) XXXX---- //////// + XXXX---- ////YYYY + -------- ////YYYY + -------- ////YYYY + -------- //////// + -------- //////// + + Als deze sprite als volgt over elkaar worden geplaatst, + volgt er een conflict: + XXXX---- + //XXXX---- + //XXXX---- + //XXXX---- + //XXZZYY + ////YYYY + ////YYYY + ////YYYY + //////// + //////// + + + Als twee sprites botsen, dan wordt in status reg. s#0 bit 5 + gezet. Als er in mode 2 wordt gewerkt kunnen de de X + coordinaten worden gahaald uit s#3/s#4, en de Y coordinaten + uit s#5/s#6. Om nu uit te zoeken om welke sprites het gaat, + zou je zelf een routine kunnen maken die de coordinaten van + de sprites met elkaar gaat vergelijken. + + MSB b7 b6 b5 b4 b3 b2 b1 b0 LSB + ---+---+---+---+---+---+---+--- + s#3 X7 X6 X5 X4 X3 X2 X1 X0 + s#4 1 1 1 1 1 1 1 X8 + s#5 Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 + s#6 1 1 1 1 1 1 Y9 Y8 + + + R E S T N O G . . . + + ...de informatie over de 5e/9e sprite op een gelijke Y as. + In mode 1 kunnen er 4 sprites en in mode 2 kunnen er 8 + sprites op een dezelfde beeldlijn worden vertoond. Als er + meer sprites worden neergezet wordt bit 6 van s#0 gezet, en + bevatten b0-b4 het 5e/9e sprite nummer. + + Een 5e/9e (en hoger) sprite wordt dan niet weergegeven. De + meeste software programmeurs (voor al in spellen) hebben dit + opgelost door het alom bekende 'knipper' effect. Hierdoor + wordt bijvoorbeel de 5e/9e sprite verwisseld met sprite 1 + waardoor deze snel om de beurt worden weergegeven. Op deze + manier zijn de sprite toch allemaal zichtbaar. + + + Als het goed is, is op deze special een assembly file + aanwezig met de naam: + "SPRITES .asc" + + Deze bevat diverse routines om de sprite basis adresen te + zetten en/of te berekenen, plus nog enkele handige routines. + In die routines worden ook subroutines gebruikt, die u zelf + kunt bijvoegen (o.a. reken routines). + + Veel spritefun! + R�man van der Meulen diff --git a/sunrise_special/6/Subdirs onder DOS1.md b/sunrise_special/6/Subdirs onder DOS1.md new file mode 100644 index 0000000..00c3cb3 --- /dev/null +++ b/sunrise_special/6/Subdirs onder DOS1.md @@ -0,0 +1,156 @@ + S U B D I R S O N D E R D O S 1 + + + Tot nu toe was het onmogelijk om onder DOS1 in + subdirectory's te kijken, laat staan om ze te gebruiken. + Maar nu zijn er Japanse programmaatjes die dit wel mogelijk + maken. Het systeem is geheel compatible met MSX-DOS2 en + MS-DOS, dus het is echt ideaal. + + + W E R K I N G + + Eerst moet je de disk die je ermee wilt gebruiken een naam + geven. Dit gebeurt met LABEL.COM. Je typt gewoon achter + LABEL de naam in, en de disk wordt zo genoemd. Ik weet niet + precies waarom dat nodig is, maar volgens mij wordt er dan + een tabelletje aangemaakt, waarin de verderop besproken + subdirectory utils de benodigde info dumpen. + + Als je LABEL.COM niet eerst gebruikt, weigeren de + DIR-utility's om te werken. Je krijgt dan een Japanse + foutmelding - die ik eerst niet helemaal snapte ("No volume + table"). + + + C H D I R . C O M + + CHDIR staat uiteraard voor CHange DIRectory, en je kunt er + dus mee van directory veranderen. Als je geen directory + achter CHDIR opgeeft, wordt de huidige directory afgebeeld. + Dat is wel handig, want die krijg je niet te zien bij het + commando DIR. Gelukkig neemt DIR de subdirectory's wel al + mee in het overzicht van de files, met erachter vermeld + "". + + + M K D I R . C O M + + Dit staat natuurlijk voor MaKe DIRectory, en hiermee kun je + dus de directory's aanmaken. Ook hier moet je weer gewoon + achter MKDIR de aan te maken directory opgeven. + + + R M D I R . C O M + + En tenslotte nog ReMove DIRectory, juist ja, het verwijderen + van - lege - subdirectory's. + + + H O E K A N D A T N O U ? + + Als je even goed nadenkt, is het natuurlijk onmogelijk om al + deze DIR-utils te gebruiken. Als je immers eenmaal in een + andere directory zit, kun je de utility's zelf niet meer + gebruiken, omdat die uiteraard in de root-dir - de stam - + staan. En je zou dan dus moeten resetten om terug te keren. + + Hiervoor heeft de Japanse programmeur echter een oplossing + bedacht: in SETDIR.SYS kun je de bestanden plaatsen die in + elke directory komen. Uiteraard dienen tenminste de volgende + files erin te staan: + + COMMAND.COM + MSXDOS.SYS + CHDIR.COM + MKDIR.COM + RMDIR.COM + SETDIR.SYS + + Maar het is natuurlijk altijd handig om andere utility's, + zoals TED erin te zetten. + + Er zijn echter nog meer handige programmaatjes die bij deze + verzameling horen: + + + R A M D I S K . C O M + + Dit is natuurlijk een RAMdisk programma voor DOS1. Het is + best wel handig, omdat het niet terug naar BASIC gaat, en + toch wel dezelfde kwaliteiten heeft als de Nederlandse + RAMdisk programma's - behalve als je natuurlijk toch al de + hele MemMan gebruikt, want dan is RAMdisk 4.00 het beste. + + Bij RAMDISK.COM kun je niet de hoeveelheid te gebruiken + geheugen opgeven, maar wel welk geheugen gebruikt moet + worden: + + /V : alle VRAM + /M : alle (main) RAM + Hierachter kan eventueel het slotnummer opgegeven + worden, als je maar ��n memory mapper wilt gebruiken + als RAMdisk. Bijvoorbeeld RAMDISK /M 2-2 voor de memory + mapper in slot 2.2 (het derde gleufje van de + slotexpander, als die in slot 2 is gestoken). + + /H : iets met ROM + Misschien dat het hiermee mogelijk is de ROMdisk van de + FS-A1GT alsnog te gebruiken onder DOS1, of zoiets. Iets + anders lijkt me niet zo logisch - maar wie het weet mag + het me laten weten! + + Verder kun je nog met R (dus zonder streepje!) opgeven dat + de RAMdisk drive A: moet zijn. Dan krijg je dus: + + RAMdisk FDD1 ( FDD2 ) + A: B: ( C: ) + + Ook kun je opgeven vanaf welk geheugenadres het RAMdisk zich + mag plaatsen. Dit doe je als volgt: + + RAMDISK S xxxx + + Waarbij xxxx het hexadecimale adres is. Bijv. E000. + + + Voorbeeld: + RAMDISK R /M/V + + Dit maakt een RAMdisk aan die alle aanwezige RAM (VRAM en + memory mapper) gebruikt, en er dan drive A: van maakt. + + + S E T B O O T . C O M + + Met dit programma kunnen bij het opstarten bepaalde dingen + veranderd worden. De bootsector wordt door dit programma + namelijk naar wens aangepast. Maar kijk wel uit hiermee, het + programma wil ook meteen je hele disk formatteren - en dat + kan best wel pijnlijk zijn, zo leert mijn ervaring hiermee. + + Achter SETBOOT kun je de volgende letters gebruiken. Het + NIET gebruiken van deze letters impliceert dus meteen dat de + omgekeerde handeling gebeurt. + + D : geen [CTRL] indrukken zorgt voor 2 + drives + K : het KANA lampje aan (alleen bij + Japanse computers) + C : het CAPS lampje aan + H : weer iets met ROM (zie ook bij RAMdisk + de optie /H) + + + Voorbeeld: + SETBOOT B:C + + Nu wordt de bootsector van de disk in drive B: zo aangepast + dat het CAPS lampje altijd aangaat, en dat je alleen 2 + drives kunt gebruiken als je [CTRL] WEL inhoudt. Het KANA + lampje gaat nu dus ook niet aan. Dit is best wel handig voor + mensen met maar ��n drive. Die virtuele drive kost normaal + namelijk meer dan 1 kB BASIC ruimte, en het is lastig om + altijd [CTRL] ingedrukt te moeten houden bij het opstarten. + + Kasper Souren diff --git a/sunrise_special/6/Turbo Modula-2.md b/sunrise_special/6/Turbo Modula-2.md new file mode 100644 index 0000000..5e9db59 --- /dev/null +++ b/sunrise_special/6/Turbo Modula-2.md @@ -0,0 +1,130 @@ + T U R B O M O D U L A - 2 + + + Op de disk staat MODULA2.PMA, met daarin de Turbo Modula-2 + compiler van Borland! Nu vraag je je misschien af: "Is dat + niet illegaal?" Volgens Borland zelf in ieder geval niet! + Borland ondersteunt hun CP/M software niet meer, omdat dat + betekent dat ze ook service en updates moeten geven. Daarom + doen ze net of het niet bestaat, en als je toch vraagt hoe + je eraan kunt komen, krijg je te horen dat je het maar van + iemand moet kopi�ren! + + Enfin, nadat we dit (waargebeurde) verhaal hadden gehoord + besloten we na enig overleg om de Modula-2 compiler gewoon + op de Special te zetten, om zo de drempel om met Modula-2 te + beginnen zo laag mogelijk te houden. + + + T U R B O + + Net als bij Turbo Pascal zijn er een aantal verschillen + tussen Turbo Modula-2 en standaard Modula-2. Het belang- + rijkste verschil is dat de read/write statements net als bij + Turbo Pascal maar in tegenstelling tot standaard Modula-2 + wel tot de taal behoren! + + Bij standaard Modula-2 zitten de read/write statements in + losse modules, wat betekent dat je voor elk type een aparte + read/write nodig hebt! + + In standaard Modula-2 kun je bijvoorbeeld zoiets tegenkomen: + + WriteString("Lengte: "); + WriteReal(Lengte); + WriteLn; + + In Turbo Modula-2 is het net als bij Turbo Pascal: + + WRITELN("Lengte: ", Lengte); + + Wat toch een stuk fijner is! De onhandige read/write + statements van Modula-2 is zelfs de belangrijkste reden dat + Turbo Pascal veel populairder is dan Modula-2! Maar gelukkig + hebben wij Turbo Modula-2 voor MSX en hebben wij daar geen + last van. + + Modula-2 heeft geen stringtype, je moet zelf strings maken + met ARRAY OF CHAR. Dit is bij Turbo Modula-2 nog steeds zo, + wel kunnen zulke ARRAYs OF CHAR nu worden vergeleken en + geassigned. Het onderstaande kan in Turbo Modula-2 dus wel + en in standaard Modula-2 niet: + + String := "Modula-2"; + IF String = "Turbo Pascal" THEN + WRITELN("Dit kan niet!"); + END; + + Er zijn nog meer verschillen met standaard Modula-2 (zoals + meerdimensionale open-array parameters), maar een standaard + Modula-2 source zal normaal gesproken gewoon kunnen worden + gecompileerd. Let op: de standaardmodule Storage heet bij + Turbo Modula-2 STORAGE! In hoofdletters dus, let daar op! + + + D E C O M P I L E R + + De Turbo Modula-2 compiler is een ge�ntegreerd pakket met + ingebouwde editor en 'library manager'. Als de compiler een + fout tegen komt in de source springt hij automatisch naar de + editor, als je de fout hebt verbeterd gaat het compileren + gewoon door! + + Als je een source compileert wordt er nog geen uitvoerbare + .COM file van gemaakt, je moet hem daarvoor eerst nog + linken. + + Eigen ML-routines kunnen in binaire vorm (.COM, moet wel + relocatable zijn!) of als relocatable (.REL) worden + toegevoegd! Dit is bij grotere routines veel handiger dan + bij Turbo Pascal, waarbij met pure hex-codes wordt gewerkt. + + + M E N U + + Je start Turbo Modula-2 door achter de DOS prompt "M2" in te + typen. Je komt nu in het hoofdmenu terecht. Je kunt hier een + keuze maken door de letter in te toetsen die als hoofdletter + in de menu-optie staat. De opties in het kort: + + Work file Geef de naam van de huidige werkfile op + Edit Ga naar de editor + Compile Compileer de huidige source + Run Voer een .MCD file uit + eXecute Voer een .COM file uit + Link Maak Z80-code + Options Instellingen wijzigen + Quit Verlaat de compiler + liBrarian Library manager + Dir Directory + Filecopy Kopieer file(s) + Kill Wis file(s) + reName Hernoem file(s) + Type Bekijk file + + Het interne codeformaat van de compiler is .MCD. Als je een + definition module compileert wordt het een .SYM file, een + implementation module wordt een .MCD file. Je kunt een + aantal .MCD's met bijbehorende .SYM's samenvoegen tot een + library met de librarian. + + + D E E D I T O R + + De editor is ingesteld als aanbevolen door Herman Post voor + de editor van Turbo Pascal in MCCM 61. De belangrijkste + toetsencombinaties zijn: + + CTRL-Y Wis regel + CTRL-N Voeg regel tussen + CTRL-K, CTRL-D Verlaat editor + + Voor de overige combinaties verwijs ik naar MCCM 61, blz. + 12. De editor is niet echt handig, dus het is misschien + fijner om TED te gebruiken voor het schrijven van het + grootste gedeelte van de source en de editor alleen te + gebruiken voor debuggen. De toetsencombinaties kunnen + eventueel naar eigen smaak worden ingesteld met INSTM2.COM. + + Stefan Boer + diff --git a/sunrise_special/6/Valburg systeem.md b/sunrise_special/6/Valburg systeem.md new file mode 100644 index 0000000..c269807 --- /dev/null +++ b/sunrise_special/6/Valburg systeem.md @@ -0,0 +1,146 @@ + V A L B U R G - S Y S T E E M + + + Het begon allemaal toen ik las dat Alex v.d. Wal Gianna + Sisters professioneel noemde, ik voelde me meteen geroepen + om ook eens iets te schrijven over mijn aanpak van grote + projecten. Maar we beginnen bij het begin. + + G I A N A S I S T E R S + + Giana Sisters is eigenlijk niet erg professioneel opgezet. + Ik ben begonnen in WBASS2 met de scroll-routine. Dat was een + heel elementair iets dat ik af moest hebben voordat er met + iets anders kon worden begonnen. Daarna kwamen + achtereenvolgens erbij: de sprite routines, besturing van de + speler en botsen van de speler tegen de achtergrond, + vijanden, interactie van vijanden met de speler, en + vervolgens werden alle onderdelen uitgewerkt tot het spel + dat het nu is. + + Ik heb natuurlijk ook een editor gemaakt om de velden in te + ontwerpen, en een converter om de SCREEN 4 karakters aan te + maken. Langzamerhand bleek dat de source te groot werd om + nog in WBASS2 mee te werken. Ik moest toen tegen mijn zin in + overschakelen op GEN80. Dus eerst naar DOS, de tekst + editten, GEN80, naar BASIC, uitproberen, werkt niet, naar + DOS, etc.. Achteraf gezien vrij omslachtig. + + Op een gegeven moment heb je dan de speelroutine zo'n beetje + wel af en moet je bezig gaan met een programma eromheen dat + highscores doet, stages inlaadt, etc.. Ik heb er toen voor + gekozen om daar een los programma van te maken dat de main + in kon laden. Geen kernel dus, geen eigen BIOS, niks + daarvan. Wel werd de BIOS bijna geheel gepasseerd. Ik + gebruikte hem alleen nog voor schermwisselingen en joystick + poort uitlezen. + + Het resultaat mag er zijn. Een echte Mario-kloon waar heel + MSX'end Nederland zo op zat te wachten. Maar veel kritiek + kreeg ik wel. Het was grafisch niet mooi genoeg, ik had niet + genoeg fade-in en fade-outs erin zitten en Loek van Kooten + gaf nog kritiek op het uit Friesland afkomstig zijn van de + club. ("gemene valletjes bedacht door de makers, maar die + komen dan ook maar uit Friesland") + + + T O T A A L A N D E R E A A N P A K + + Er is nogal wat veranderd na dat tweede spel. Ik zal nu + eindelijk to the point komen en vertellen hoe ik vind dat + het echt moet, en waarom. + + Allereerst ben ik me vreselijk gaan afzetten tegen WBASS2. + Door het gemis van MACRO's, relocatable files, een goede + INCLUDE functie, door het te kleine werkgeheugen en doordat + het onder BASIC werkt. Snel gaat het wel, en voor beginnende + ML programmeurs of demomakers is het helemaal zo gek nog + niet. + + Programma's maken gaat het beste onder DOS. Liefst met + ramdisk of HD en met een tR of 7 MHz als het even kan. DOS + heeft het voordeel dat er 2 keer zoveel ruimte beschikbaar + is als onder BASIC. Natuurlijk kan je onder BASIC ook de + interpreter wegschakelen en de BIOS weghalen, maar onder DOS + is dat al gebeurd, dus waarvoor al die moeite? En als je + toch de BIOS wilt gebruiken dan doe je gewoon een + interslotcall. Over het algemeen zal je de functies die snel + moeten zijn toch al wel zelf hebben gemaakt. + + Ook draaien programma's die je onder DOS hebt gemaakt ook + meteen goed vanuit de bootsector. Gewoon het BDOS jump adres + naar 05H copieren en starten maar. Alle RAM pagina's staan + al voorgeschakeld. Of rename je de .COM file liever als + COMMAND.COM? MSXDOS.SYS erbij en dan is het meteen klaar. + + Dan het idee van een eigen kernel. Het idee is leuk en + klinkt heel professioneel en interessant, maar eigenlijk is + het alleen handig bij diskmagazines. Daar heb je nl. vaak + heel veel programma's met allemaal dezelfde routines. In + andere gevallen komen de routines maar een keer voor en is + het alleen maar onhandig om al die overtollige + niet-gebruikte routines in pagina 0 mee te sjouwen. + + Daarom beveel ik ook aan om libraries te maken met daarin + alle routines die je anders in een BIOS/kernel zou stoppen. + Het enorme voordeel hiervan is dat precies de routines die + jij in je programma aanroept uit de library worden gevist en + aan je programma worden geplakt! Zo gebruik je dus niets te + veel aan geheugen en hoef je ook geen kernel in te laden! + Voor mij is dat nu al de ideale manier en volgens mij weten + een heleboel mensen niet dat een linker dat kan. Lees het + voorgaande dan nog maar eens goed want het is echt + superhandig. Een linker is een zeer vernuftig stukje + software dat modulair programmeren tot kinderspel maakt. + + Dan komen we nu bij het probleem van het filesysteem. + Eigenlijk heb ik dat hiervoor al opgelost. Gewoon een + library functie die een file op een bepaald adres kan + inladen. Als het nu op sector moet komen te staan vervang je + de library functie door een sector lader met erbij gelinkt + de data met de plaats van de files. Aan het programma zelf + hoeft niets te worden veranderd, gewoon opnieuw linken en je + programma laadt op sectorniveau. + + + P L A A T J E S E N M U Z I E K L I N K E N + + In plaats van inladen zou je natuurlijk ook de plaatjes en + muziek in je programma kunnen stoppen. Alleen zit je dan met + het probleem waar? Je kan het natuurlijk heel precies aan + het einde van je programma zetten, maar als je programma dan + wat groter wordt moet je het adres weer aanpassen en + bovendien dat hele plaatjes er weer aan CONCATten of + misschien zelfs met de hand eraan plakken als je geen DOS 2 + hebt. + + Je raadt al wat de oplossing is... linken. maak van de + muziekfile of grafische file een .REL file. Eraan linken en + de linker plakt alles precies op de juiste plaatsen aan + elkaar en vult daarna de juiste adressen in in jouw + programma. Handiger kunnen we het niet maken. + + Misschien denk je nu wel "te mooi om waar te zijn, dat duurt + veel te lang en bovendien is het alleen maar theorie. Hij + gebruikt zelf vast WBASS2". Helemaal mis! Het linken gebeurt + razendsnel. Over het algemeen doet de linker er nooit langer + over dan 30 seconde, en dan zoekt ie dus library's uit en + plakt ie plaatjes aan je programma en alles. Het tweede is + ook niet waar want zelf heb ik (samen met Jouke Dijkstra, + die mag wel eens genoemd worden) alles al in de praktijk + gebracht. Ik heb zelf al een programma gemaakt waarin in een + file alle muziek, plaatjes etc. erbij zitten en dan staat + het ook nog een op sector en wordt ingeladen vanuit de boot. + (zonder MSXDOS.SYS) + + + J A , I K W I L O O K L I N K E N + + Dat kan, join the club. Als je interesse hebt in hoe dit + alles in de praktijk in zijn werk gaat, of je hebt + belangstelling voor de library's en programma's waarmee dit + alles moet worden bewerkstelligd dan hoef je alleen maar + even contact op te nemen met mij via post, telefoon of + echomail, uploads/downloads alleen via Piramide BBS. + + Jan van Valburg diff --git a/sunrise_special/6/Waarom Modula2.md b/sunrise_special/6/Waarom Modula2.md new file mode 100644 index 0000000..827a710 --- /dev/null +++ b/sunrise_special/6/Waarom Modula2.md @@ -0,0 +1,109 @@ + W A A R O M M O D U L A - 2 ? + + + Op de vorige Special had ik aangekondigd een cursus Turbo + Pascal te starten. Dat deed ik eigenlijk bij gebrek aan + beter, want ik had liever een Modula-2 cursus aangekondigd. + Ik dacht toen dat er helaas geen Modula-2 compiler was voor + MSX, zodat we het dan maar met Turbo Pascal moesten doen. + + Een paar maanden later zag ik opeens een Modula-2 compiler + in Mari's Games BBS, die ik natuurlijk meteen heb gedownd. + Dit bleek Turbo Modula-2 van Borland te zijn! + + + F A N + + Ik ben een echte Modula-2 fan! De voordelen van Modula-2 en + Pascal zijn dat het eigenlijk de enige bekende talen zijn + die speciaal bedoeld zijn voor gestructureerd programmeren. + Natuurlijk kun je ook met Modula-2 en Pascal nog knoeien, + maar de talen nodigen in principe uit tot netheid. Dit in + tegenstelling tot C, waarin de meeste programmeurs er een + onleesbare puinhoop van maken. + + En waarom kies ik dan voor Modula-2 en niet voor Pascal? + Beide talen zijn door Niklaus Wirth ontworpen en lijken dan + ook vrij veel op elkaar. Wirth heeft Modula-2 echter later + ontworpen dan Pascal, waarbij hij een groot aantal minder + sterke punten in het ontwerp van Pascal heeft verbeterd. + Borland heeft een aantal voordelen van Turbo Pascal ten + opzichte van standaard Pascal overigens van Modula-2 + afgekeken! + + + V O O R D E L E N + + De voordelen van Modula-2 ten opzichte van Turbo Pascal + zijn: + + - Modula-2 werkt met modules, waardoor op een zeer handige + wijze modulair kan worden geprogrammeerd. De modules + worden apart gecompileerd, als je iets veranderd in een + module hoeven de andere modules dus niet opnieuw te worden + gecompileerd! (Bij Turbo Pascal is dat wel zo.) Bovendien + worden alleen de procedures die je werkelijk gebruikt uit + de module ge�mporteerd, zodat de executable niet onnodig + groot wordt. + - De structuur van IF, WHILE, etc. statements is bij + Modula-2 veel logischer waardoor je veel minder snel + fouten maakt dan bij Turbo Pascal. + - Het maakt bij Modula-2 niet uit in welke volgorde je de + procedures zet, terwijl Turbo Pascal een (onlogische) + volgorde oplegt (namelijk dat procedures die vanuit een + andere procedure worden aangeroepen erboven moeten staan, + eronder is logischer omdat je topdown programmeert). + - Modula-2 is case-sensitive en alle gereserveerde woorden + moeten met hoofdletters worden geschreven. Voor sommigen + lijkt dit misschien een nadeel, maar het is bijvoorbeeld + erg handig om een variabele Char van het type CHAR te + hebben (dat kan bij Turbo Pascal niet omdat Turbo Pascal + geen verschil maakt tussen hoofd- en kleine letters) en + het maakt de programma's beter leesbaar. Ik schrijf in + Turbo Pascal ook alle gereserveerde woorden in + hoofdletters, maar helaas behoor ik daarmee tot een + minderheid. + - Genest commentaar mag in Modula-2 wel en in Turbo Pascal + niet. Dit is erg vervelend bij Turbo Pascal, als je daar + een flink stuk van je source tussen {} wilt zetten kan dat + alleen als er geen commentaar in voorkomt. + - Modula-2 heeft 'open array' parameters, waardoor je + makkelijker universele procedures kunt maken voor arrays. + - De stapgrootte van een FOR-loop is bij Modula-2 variabel + (bij Turbo Pascal zijn alleen +1 en -1 mogelijk). + + Er zijn nog wel meer verschillen/voordelen te noemen maar + deze lijst lijkt me wel voldoende reden om Modula-2 te + prefereren boven Turbo Pascal. + + + N A D E E L + + Eigenlijk het enige nadeel van Modula-2 ten opzichte van + Turbo Pascal is dat Turbo Pascal veel meer wordt gebruikt. + Dit heeft als gevolg dat er meer aandacht voor is in de vorm + van cursussen in tijdschriften, boeken en libraries. + + Maar als dit een reden zou zijn om toch Turbo Pascal te + gebruiken, dan vraag ik me af waarom er nog MSX gebruikers + zijn. Er zijn immers veel meer PC-gebruikers... + + + A L L E E N T E K S T + + Ik hoor vaak van andere MSX'ers: ik programmeer niet in + Turbo Pascal omdat je dan geen grafische instructies hebt. + Je kunt alleen maar met (trage) READ/WRITE op een + tekstscherm werken. Dit zelfde 'nadeel' geldt ook voor Turbo + Modula-2. + + Maar natuurlijk kun je een library maken met grafische + instructies, en dat is wat ik binnenkort ga doen. Dus op + Sunrise Special #7 kun je een flinke library verwachten met + een grote hoeveelheid handige routines voor de VDP, zodat je + Modula-2 dan ook voor grafische dingen kunt gebruiken. + + Kortom, ik hoop dat een groot aantal van jullie over zal + stappen op Modula-2! + + Stefan Boer diff --git a/sunrise_special/7/Barcode.md b/sunrise_special/7/Barcode.md new file mode 100644 index 0000000..87371a9 --- /dev/null +++ b/sunrise_special/7/Barcode.md @@ -0,0 +1,238 @@ + + B A R C O D E S + + + Dit tekstje gaat over barcodes en het lezen daarvan. Het is + ook voor degenen die geen barcode reader hebben geschikt. + + Voor onze MSX computers zijn heel wat interessante + cartridges uitgebracht, zoals de cartridge met sensoren uit + Japan, de robotarm van Spectravideo, de Sanyo Lightpen (als + je die hebt, bel me dan eens!) en de barcode reader van + Philips. Aangezien ik de laatste in mijn bezit heb, ben ik + er wat mee gaan rommelen, waarvan dit artikel het resultaat + is. + + Ik ben niet de eerste die dat doet; in MCM 47 staat er een + artikeltje over, maar toen ik mijn MCM-stapel eens + uitmestte, bleek het dat nr. 47 slechts schitterde door + afwezigheid... Ik moet het dus allemaal zelf uitzoeken... + + + D E W E R K I N G + + Allereerst heb ik de reader maar eens opengeschroefd. Al het + werk wordt gedaan door een speciaal barcode IC. De gebruiker + hoeft slechts de pen over de barcode te halen en het IC + verwerkt het signaal en slaat de barcode op in een buffer. + De communicatie met de MSX verloopt via I/O poort &H18, maar + door middel van een jumper kan ook I/O poort &HB8 gebruikt + worden. We zullen dus eerst moeten weten via welke poort de + communicatie verloopt. Een handige oplossing hiervoor is het + volgende BASIC programma, dat ook op disk staat onder de + naam BAR-ADR.BAS: + + 10 P=&H18:GOSUB 40:P=&HB8:GOSUB 40:P=0 + 20 PRINT "Poort: ";HEX$(P) + 30 END + 40 IF PEEK(P)=255 THEN RETURN ELSE RETURN 20 + + N.B. Als P=0 dan is er geen barcode reader aanwezig. + + Vervolgens moeten we een (BASIC-)programma hebben om de code + ook daadwerkelijk uit te kunnen lezen. Dit staat ook op disk + onder de naam BAR-READ.BAS. + + Als we de pen over een barcode halen, dan zal de code in een + buffer worden opgeslagen. Dat betekent dat er geen commando + nodig is om het lezen te starten. Ook tijdens een programma + kan je dus een barcode inlezen, omdat de hardware het hele + zaakje afhandelt. De code blijft in de buffer staan totdat + die uitgelezen wordt of totdat een nieuwe barocde gelezen + wordt. We hoeven dus alleen de buffer uit te lezen via de + I/O poort die ingesteld is. In het vervolg van het artikel + ga ik voor het gemak uit van I/O poort &H18. Bit 7 is het + status bit. 0 betekent dat de barcode gelezen kan worden en + 1 dat het einde van de barcode bereikt is. + + We hoeven alleen iets te lezen als de code gereed staat, dus + als bit 7 laag is. Dat wil zeggen dat het getal op de I/O + poort kleiner dan 128 is. Daarom wordt de eerste regel van + het uitleesprogramma: + + 10 B=INP(&H18):IF B>127 THEN 10 + + Als dat niet zo is, dan is de waarde van belang en moet dus + bewaard worden. Uiteindelijk is het de bedoeling dan de + string B$ de code bevat. We zetten de waarde van de I/O + poort dus in B$: + + 20 B$=CHR$(B) + + Vervolgens kunnen we de rest van de code uitlezen, dus + totdat het eind van de code bereikt is en bit 7 hoog wordt + (en de waarde van de I/O poort dus groter dan 127 wordt): + + 30 B=INP(&H18):B$=B$+CHR$(B AND 127): IF B<128 THEN 30 + + Merk op dat de waarde waarbij bit 7 geset wordt nog wel + meetelt! Je moet dus eerst de waarde opslaan en DAARNA pas + kijken of die groter dan 127 wordt (en dus de laatste was). + De AND 127 dient daar voor, want een AND 127 maakt immers + altijd bit 7 laag en zorgt er dus voor dat ook de laatste + waarde juist is. + + Vervolgens geven we een BEEP ten teken dat de code ingelezen + is en we printen de string op het scherm. + + 40 BEEP:PRINT B$ + + De code bevat eerst een letter. Dit geeft het type barcode + aan. Er zijn namelijk verschillende manieren om een barcode + te maken. Leuk om te weten, veel heb je er niet aan. In de + meeste gevallen (zeker bij supermarktprodukten) zal het een + D zijn. Wat echter wel interessant is aan die letter is of + het een hoofd- of kleine letter is, of anders gezegd : of + bit 5 van de eerste waarde van de code geset is of niet. Bit + 5 geset betekent namelijk dat de barcode van rechts naar + links is gelezen en Bit 5 gereset (laag) betekent dat de + barcode van links naar rechts is gelezen. + + + D E O P B O U W V A N E E N C O D E + + Nu het mogelijk is om een barcode in te lezen, gaan we eens + kijken hoe die opgebouwd is. Om de code optisch te kunnen + lezen, wordt elk getal weergegeven door 2 witte en 2 zwarte + strepen, elk met een lengte varierend tussen 1 en 4 modulen. + Hoe de code precies gecodeerd is, heb ik niet kunnen + achterhalen. + + De cijfers zelf hebben ook nog een betekenis, als ze + tenminste aan de internationale norm voldoen. Dat zal bij + supermarkt produkten zeker het geval zijn. Soms gebruiken + bedrijven etc. eigen (interne) streepjescodes. Een mooi + voorbeeld is de handleiding van mijn CM11342 RGB-monitor van + Philips, daarin worden niet alleen cijfers maar ook letters + gebrukt; het typenummer staat in de streepjescode. In de + Times staat een voorbeeld, DEMO2, van zo'n afwijkende + streepjescode. Deze is afkomstig van een zending van Philips + en bevat mijn adres. Dit soort codes is dus niet standaard. + + Binnen de standaard kunnen we 3 types onderscheiden: + + 1. De code voor boeken + + Deze beginnen met 97 en de rest is ISBN-nummer. Het laatste + cijfer is een controlecijfer, meer hierover bij 2. + + 2. De code voor produkten per stuk (met een vaste prijs) + + Deze zijn op allerlei etenswaren te vinden. De eerste twee + cijfers bevatten de landcode, bijvoorbeeld 87 is Nederland. + De volgende 5 cijfers bevatten de producentcode, + bijvoorbeeld 10400 is Albert Heijn Huismerk, de volgende 5 + cijfers bevatten het artikelnummer, en het laatste cijfer is + een controlecijfer. Als je dit cijfer optelt bij de som van + de even cijfers (excl. controlegetal) en 3 maal de som van + de oneven cijfers (excl. controlegetal) precies een tiental + opleveren. + + Om het een en ander te verduidelijken volgt een voorbeeld. + We gebruiken de in de Times afgebeelde code, DEMO1: + + 2263182000062 + + Dat shrijven we voor het gemak even als : + + 22 63182 00006 2 + + Het controle cijfer is zoals je ziet 2. Controle of het + klopt: + + Som v.d. even cijfers : 2+2+6+8+2+6 = 26 + 3 keer de som v.d. oneven cijfers : 3*(3+1) = 12 + Het controlegetal = 2 + + ---------------------------------------------------- + 40 + + En dat is een tiental! Het komt ook voor dat een bepaald + artikel 1 code heeft voor producent/artikel. De code is dan + 5 tekens korter. + + + 3. De artikelen per gewicht + + Van bepaalde produkten is de prijs niet van te voren bekend, + zoals groente en fruit, kaas, brood, vlees/vleeswaren, + zelfbedieningssnoepgoed etc. Op de bon verschijnt dan vaak + een streepjescode. Deze heeft als landcode een cijfer tussen + 20 en 29. de volgende 5 cijfers geven het product aan, + vervolgens 5 cijfers voor de prijs en tenslotte het + controlecijfer. + + Als voorbeeld een code van Nasivlees voor � 4.36: + + 2221001004363 + + 22 : Geeft aan dat het om een artikel uit de groep "per + gewicht" gaat + 21001: Nasivlees + 00436: De prijs (in centen) + 3 : Controlecijfer + + + D E S O F T W A R E + + Al het bovenstaande is verwerkt in een programma, dat op de + disk staat onder de naam BARCODE.BAS. Het is geschikt voor + alle MSX'en en het werkt op SCREEN 0 met WIDTH80 of WIDTH40. + Dit programma is in BASIC, maar voor assembler of een andere + programmeertaal geldt natuurlijk precies hetzelfde. + + Dit programma herkent de hierboven genoemde soorten. Het + programma gebruikt de datafile BARCODE.DAT. Als het een + barcode herkent, dan wordt de informatie op het scherm + gezet, anders wordt je gevraagd de gegevens in te typen. + Landcodes en producentcodes die al ooit ingegeven zijn, + worden herkend, dus van sommige dingen hoef je alleen het + artikel in te geven. + + De besturing werkt geheel met de reader. Daarvoor zijn er in + de Times 5 besturingsstreepjescodes afgedrukt. Dit zijn + gewoon afgeknipte bonnetjes uit de Albert-Heijn + groenteweegschaal, maar ze worden door het programma herkend + als zijnde een besturingscode. In theorie is het mogelijk + dat groente of fruit van Albert Heijn als besturingscode + wordt gezien, maar in de praktijk is dat vrijwel onmogelijk, + omdat ik een gewichtje van 10 gram gebruikt heb en speciale + soorten groente/fruit. Want wie koopt er nou 10 gram appels? + + Als eerste, voor het opstarten van de software, moet je 2 + keer over een streepjescode heengaan. Als je de computer + aanzet, staat er namelijk rommel in de buffer van de reader + en als je een code leest is dat weg. Daarna kun je het + programma starten met RUN"BARCODE.BAS". + + Op disk staat een voorbeeldfile met een aantal bekende + produkten erin, zodat je niet alles hoeft in te typen en er + ook in het eerste begin al wat herkend wordt. Hierbij moet + je denken aan Albert Heijn en Melkunie melk, Pickwick Thee, + DE Koffie etc. Het is ook mogelijk om zonder file te + beginnen, u kunt BARCODE.DAT dus ook wissen. Het programma + maakt dan een nieuwe aan zodra je iets ingeeft. + + In het begin van het programma moet u een barcode ingeven. + Op dat moment zijn ook de keuzes STOP en HELP mogelijk. In + de rest van het programma wordt aangegeven welke keuzes je + kunt maken. + + Het programma is nog niet volmaakt, zo kunt je niets + verbeteren en ook niets wissen. Als je zin hebt om het + programma uit te breiden, ga je gang! Ik zou het leuk vinden + als je het ons opstuurde, zodat het op de volgende Special + geplaatst kan worden. Ook andere toepassingen met behulp van + de barcode reader zijn welkom. Stuur deze dan naar mijn + adres en niet naar de postbus. + + Rob Augusteijn diff --git a/sunrise_special/7/CMD Mode V9958.md b/sunrise_special/7/CMD Mode V9958.md new file mode 100644 index 0000000..8f7343a --- /dev/null +++ b/sunrise_special/7/CMD Mode V9958.md @@ -0,0 +1,148 @@ + C M D M O D E V 9 9 5 8 + + + De videochip van de MSX2+ en de MSX turbo R (de V9958) heeft + er ten opzichte van de V9938 drie nieuwe registers bij + gekregen. Dit zijn: + + 7 6 5 4 3 2 1 0 + R#25 - CMD VDS YAE YJK WTE MSK SP2 + R#26 - - HO8 HO7 HO6 HO5 HO4 HO3 + R#27 - - - - - HO2 HO1 HO0 + + De betekenis van de bits: + + HO0-HO8: horizontaal scrollen, bij HO0-HO2 is rechts + de positieve richting en bij HO3-HO8 is + links de positieve richting + SP2: scroll horizontaal met 2 pagina's als dit + bit gezet is, met 1 pagina als het 0 is + MSK: de scroll hapt normaal aan de linkerkant, + met dit bit gezet worden 8 pixels aan de + linkerkant afgedekt + WTE: als dit bit gezet is, wordt de toegang tot + alle VDP poorten in de WAIT stand gezet + als de CPU met het VRAM bezig is. Dit + gebeurt niet in andere gevallen waarbij dit + wel handig zou zijn zoals terwijl de VDP + met een commando bezig is, terwijl de eerste + byte van een registeraccess al ontvangen is + of als de eerste byte van een paletaccess + al ontvangen is + YJK: YJK mode aan/uit (SCREEN 12) + YAE: YAE mode aan/uit (SCREEN 10/11) + VDS: met dit bit kun je het CPUCLK signaal + vervangen door het VDS signaal, wat het nut + daarvan is, is onbekend + CMD: als dit bit gezet is kunnen commando's ook + in SCREEN 0-4 worden gebruikt, waarbij de + parameters zo moeten worden ingesteld alsof + SCREEN 8 actief is + + + C M D M O D E + + Over het laatstgenoemde bit (bit 6 van R#25) gaat dit + artikel. Iedereen die het V9958 Technical Data Book of een + tekst over de V9958 registers heeft gelezen weet dat dit bit + bestaat, maar ik heb nog nooit gehoord dat iemand het + gebruikt! En toch kun je er hele leuke dingen mee doen! + + Bij de V9938 en als het CMD bit 0 is bij de V9958 kun je + alleen commando's gebruiken in SCREEN 5 en hoger. Als je het + CMD bit echter hoog maakt, kun je ook commando's gebruiken + in SCREEN 0-4! + + Nu moet je niet denken dat je lijnen kunt trekken in SCREEN + 0 of dat je kunt kopi�ren zoals je zou verwachten in SCREEN + 2, want dat is natuurlijk onzin. Je kunt niet zoiets als + COPY(10,15)-(20,35)TO(100,90) doen in SCREEN 2, omdat het + geen bitmap mode is. + + De truuk is dat de VDP bij het uitvoeren van de commando's + net doet alsof SCREEN 8 actief is! Je moet dus alles + omrekenen naar de VRAM indeling van SCREEN 8. + + Een paar voorbeeldjes zullen dit duidelijk maken. We gaan er + steeds van uit dat het CMD bit is gezet. Stel je wilt een + "A" zetten op positie (0,0) in SCREEN 0:WIDTH 80. Dan kan + dat met VPOKE 0,65 of met LOCATE 0,0:PRINT "A". Maar het kan + ook met PSET(0,0),65! Helaas niet in BASIC want die geeft + nog steeds een Illegal function call, maar wel als je het + rechtstreeks met de commando registers doet! + + Nu willen we een B zetten op positie 8,17. Dat kan dus NIET + met PSET (8,17),66!!! Je moet namelijk denken aan de VRAM + indeling van SCREEN 8. Het adres van 8,17 is 8 + 17*80 = + 1368. Nu moet je dit omrekenen naar het pixel in SCREEN 8 + dat op dat adres staat. X = 1368 MOD 256 = 88, Y = 1368 \ + 256 = 5. Dus met PSET(88,5),66 zet je een B op positie 8,17. + + + W A T H E B J E E R A A N ? + + Wat heb je hier aan zul je denken? Wel, aan PSET heb je niet + veel en aan LINE ook niet. Maar met HMMM (COPY) en HMMV + (LINE,BF) kun je bepaalde dingen een stuk sneller en + handiger doen! + + Bijvoorbeeld het scherm bewaren om het later weer te + herstellen. Met een HMMM kun je het scherm naar een ander + stuk VRAM kopi�ren. Het neemt 24*80 = 1920 bytes in beslag, + dat komt overeen met 7.5 lijnen in SCREEN 8, dat moeten we + naar boven afronden naar 8. Dus doen we COPY(0,0)-(255,7) TO + (0,128). Nogmaals, dit kan niet met het BASIC commando COPY + worden gedaan, ik gebruik alleen deze notatie voor de + duidelijkheid. Je moet dit zelf omzetten naar de juiste data + om naar register R#32 t/m R#46 te sturen: + + DB 0,0,0,0 ; source + DB 0,0,128,0 ; destination + DB 0,1,8,0 ; size + DB 0,0,#D0 ; HMMM + + Er wordt zo nog iets meer gekopieerd (2048 bytes om precies + te zijn), maar dat maakt niet uit. Met precies de + omgedraaide copy kun je het scherm nu weer zeer snel + herstellen. Deze methode kost geen RAM om het scherm op te + slaan (wel VRAM natuurlijk maar in SCREEN 0-4 gebruik je + toch alleen maar de eerste 16 kB) en wat belangrijker is: + het kost weinig processortijd! Je hoeft alleen maar die 15 + bytes naar de commandoregisters te sturen en de VDP doet de + rest van het werk. Als je het 'normaal' programmeert kan dat + nooit zo snel! + + Met HMMV kun je het scherm snel vullen met een bepaald byte. + Je kunt het scherm bijvoorbeeld in een oogwenk met A's + vullen, veel sneller dan je dat ooit op een andere manier + (gewoon met VPOKEn) zou kunnen doen. De commandodata ziet er + dan zo uit: + + DB 0,0,0,0 ; dummy + DB 0,0,0,0 ; destination + DB 0,1,8,0 ; size + DB #41,0,#C0 ; HMMV met #41 (='A') + + Hetzelfde resultaat kan ook bereikt worden door de VDP klaar + te zetten voor VRAM schrijven vervolgens 1920 maal OUT + (#98),#41 doen, maar dat kost veel meer moeite voor de CPU + en duurt bovendien langer. + + Enfin, je kunt zelf wel bedenken wat er nog meer mogelijk is + met de CMD mode, bijvoorbeeld in SCREEN 4. Je kunt misschien + ook leuke dingen doen met logische operaties, denk erom dat + je dan wel LMMM etc. moet gebruiken. Ik heb al zitten denken + voor toepassingen bij de blinkmode van SCREEN0:WIDTH 80, + maar ik geloof niet dat dat handiger gaat dan de routines + die al eerder op de Special hebben gestaan. + + + N A D E E L + + Een nadeel van de CMD mode is dat hij alleen op de V9958 + zit, en programma's die in SCREEN 0-4 worden gemaakt meestal + ook voor MSX2 zijn. Maar er zijn natuurlijk uitzonderingen + zoals een MODplayer, en daarbij zou je dit zeer goed kunnen + gebruiken. + + Stefan Boer diff --git a/sunrise_special/7/Diskette elende.md b/sunrise_special/7/Diskette elende.md new file mode 100644 index 0000000..f189039 --- /dev/null +++ b/sunrise_special/7/Diskette elende.md @@ -0,0 +1,299 @@ + D I S K E T T E E L L E N D E + + + Iedere MSX'er heeft dit waarschijnlijk al eens meegemaakt; + een disk die na het saven van een file 'kapot' is doordat + tijdens de save aktie van diskette gewisseld is. Dit + probleem is al heel lang bekend (de oplossingen ook + overigens) en ik vertel dan ook weinig nieuws, maar ik heb + nog nooit ergens na kunnen lezen wat er allemaal precies + fout gaat. + + Ik wil me hier vooral op MSXDOS-1 richten omdat dit voor + diskettes de grote boosdoener is. Diskettes kunnen in + tegenstelling tot hun grotere broers, de harddisks uit hun + gleuf geknikkerd worden. Dat is op zich heel handig, maar + het probleem is dat de BDOS hier praktisch niet achter kan + komen. De BDOS is namelijk blind voor onaangekondigde + diskwisselingen. Snapt u nu waarom een Apple Macintosh geen + eject knop heeft? Het enige wat de BDOS kan zien is dat er + tijdens een diskaktie geen disk in de drive zit, waarna deze + kan vragen om het ding weer terug te plaatsen. Het woordje + 'deze' in de vorige zin is in dit verhaal van cruciaal + belang. De BDOS gaat er nl. vanuit dat tijdens kritieke + akties altijd de fysiek gelijke diskette in de drive zit. + + Theoretisch is het mogelijk dat de BDOS ook daadwerkelijk + controleert of dit het geval is, maar dat zou een diskaktie + zo traag maken dat iedereen nog vrolijk met cassettetapes + zou werken omdat die sneller zouden zijn. De BDOS eist dus + een bepaalde discipline van de gebruiker om tijdens kritieke + diskakties NOOIT van diskette te wisselen. Ik ben echter van + nature een onderzoeker (lees: eigenwijs) en heb eens gekeken + naar wat er nu precies mis kan gaan. + + + H E T L E Z E N V A N E E N F I L E + + Het inlezen van een file begint met het openen ervan. Bij + DOS1 worden nu de 3 FAT sektoren en de directorysektor waar + de te laden file in genoemd is in het geheugen geladen en + die blijven daar ook. Vervolgens kan de file gelezen worden + waarbij in het geheugen 1 sektor met laadgegevens wordt + bijgehouden. Dit wordt gedaan om bv. 4 bytes uit de file te + kunnen lezen. Eerst wordt de sektor ingeladen en vervolgens + worden de 4 bytes naar het DMA gekopieerd. + + Tijdens het inladen kan de gebruiker tot de ontdekking komen + dat dit een oude versie van de file is waarna hij de disk in + een reflex uit de drive neemt. Indien hij deze na protesten + van de BDOS terug stopt, dan is er niets aan de hand. Stopt + hij echter een andere disk terug in de drive met de nieuwere + versie van de file, dan gaat het fout. Alle informatie over + waar de file precies op de disk te vinden is staat nl. al in + het geheugen (FAT + dir.sektor) en op deze nieuwe disk kan + deze file wel op een heel andere positie staan. In dit geval + gaat het lezen dus wel door, maar wordt alleen rotzooi + gelezen. + + Geconcludeerd mag worden dat het wisselen van diskettes + tijdens een laadaktie resulteert in een fout ingelezen file, + maar dat de diskettes zelf heel blijven. Hoe anders is dit + bij een schrijfaktie. + + + H E T S C H R I J V E N V A N E E N F I L E + + Tijdens het cre�ren van een file zoekt de BDOS de directory + sektoren af naar een lege positie voor de nieuwe file. Zodra + een plaats gevonden is wordt o.a. de filenaam alvast + ingevuld. De sektor waar de directory entry in terecht komt + blijft in het geheugen staan. Nu wordt in de FAT naar een + geschikte startpositie voor de file gezocht. De FAT wordt + overigens ook in het geheugen gelezen. + + Laten we zeggen dat de file 1kB lang is en dat de eerste 128 + bytes nu weggeschreven worden waarbij niets fout gaat. Nu + haalt een onverlaat echter de disk uit de drive waarna de + volgende 128 bytes geschreven worden. Wat zal er volgens jou + gebeuren tijdens deze tweede schrijfaktie? Een disk-offline + melding misschien? + + FOUT!! De schrijfaktie gaat wonder boven wonder goed. Dat + komt omdat ook tijdens een schrijfaktie ��n sektor met + informatie in het geheugen wordt bijgehouden en omdat een + sektor 512 bytes groot is, wordt deze buffer nog niet naar + disk geflushed. + + Nu wordt het resterende deel van de 1kB file in 1 keer + weggeschreven en komt de diskdrive dus wel degelijk in + aktie. Hier doen zich drie potenti�le foutsituaties voor, te + weten: + - Disk offline + - Disk full + - Physical I/O error (kras op de magnetische laag etc.) + + In een eerder artikel op Sunrise Magazine Special #4 heb ik + al eens geprobeerd uit te leggen hoe de error handling van + de BDOS werkt (met die dubbele pointer constructie etc.) Bij + een disk offline wordt nu naar een eventueel ge�nstalleerde + error handler gesprongen. Zo ook bij een fysieke I/O error. + Bij een disk full wordt echter alleen register A = 1 + (MSXDOS-1 call) gemaakt en wordt naar de aanroepende routine + terug gesprongen. + + De vraag op dit punt is, wat moet je nu doen? Indien er een + disk offline is geweest die nu is opgelost, maar de persoon + een andere disk in de drive heeft gestopt, dan is de kans + 99.99% dat deze nieuwe disk bij de minste of geringste + volgende diskaktie onherstelbaar beschadigd raakt doordat + zowel de FAT als de directory sektor van de andere disk op + de huidige geschreven worden. + + Even terug naar de vraag: "wat nu te doen ?". Indien de file + wordt gesloten, dan wordt de in het geheugen opgeslagen + directorysektor teruggeschreven naar de disk. Dit wordt ook + met de FAT sektoren gedaan. De nieuwe disk wordt dus met + voor hem onzinnige informatie gevuld, maar indien de + originele disk is teruggestopt dan gaat het (uiteraard) + goed. + + Indien de hele schrijfaktie domweg afgebroken wordt, dan zal + de nieuwe disk niet vernield worden, of wel ?? Het antwoord + daarop is dat deze disk in eerste instantie inderdaad heel + blijft. Tijdens mijn testjes heb ik in die situatie eens de + directory opgevraagd en zag tot mijn stomme verbazing de + directory van de schijf die ik net gewisseld had op mijn + beeldscherm verschijnen. (Opm: De totale directory van die + schijf pastte in 1 sektor) De BDOS had kennelijk niet door + dat er een andere disk in de drive was gestoken. Of dit + onder DOS-2 ook het geval is weet ik overigens niet, maar ik + kan me voorstellen dat het hier wel goed gaat omdat hier met + Volume-IDs gewerkt wordt. + + Waarom kijkt de BDOS in deze situatie niet naar de disk om + te kijken of deze misschien gewisseld is? Anders doet hij + het immers altijd (het zou niet best zijn als dat niet + gebeurde). Het enige wat de oorzaak van dit probleem kan + zijn is het feit dat de file waarop de schijfaktie fout ging + nooit gesloten is. De BDOS neemt immers aan dat een diskette + alleen tussen het lezen en schrijven van komplete files + gewisseld wordt. Het domweg afbreken van de schrijfaktie + omdat er iets fout ging is dus NOOIT goed. + + Iets anders is BDOS call 13; de drive reset. Indien deze + call wordt uitgevoerd voordat een gecre�erd bestand gesloten + is, dan gaat het toch fout doordat o.a. de FAT sektoren weer + worden teruggeschreven. In deze situatie dus niet gebruiken. + + + D E M O R A A L + + De moraal van dit verhaal is dat indien je een file cre�ert, + je deze ook moet sluiten. Doe je het niet, dan verschuif je + de ramp alleen maar in tijd naar voren, maar hij zal komen ! + Dat hierdoor diskjes vernield kunnen raken doodat ze + tussentijds gewisseld worden is jammer, maar doe je het niet + dan biedt alleen het uitzetten van de computer een garantie + dat de disk bij de volgende diskaktie in orde blijft. Het + zal hem wel aan mij liggen, maar de melding "Please reset + your MSX before continuing" lijkt me alleen in Metal Gear + grappig, maar niet in een tekstverwerker. + + Wat dient er nu te gebeuren indien een disk schrijfaktie + afgebroken wordt door de gebruiker (disk offline met + (A)bort) of de BDOS (disk vol)? Welnu, als eerste moet de + file gesloten worden. Daarna moet de gemaakte rotzooi nog + opgeruimd worden, door de aangemaakte file te deleten. Als + dat gebeurt is, is er niets aan de hand en kan de komplete + aktie later nog eens herhaald worden op een disk die meer + kans van slagen biedt. + + + P R O G R A M M E U R S E N D I S K E T T E S + + Gebruikers moeten weten dat ze tussen het cre�ren van een + file en het sluiten ervan met hun tengels van de diskdrive + af moeten blijven. Programmeurs moeten er met wat praktische + programmeer psychologie voor zorgen dat mensen niet in de + verleiding komen om het toch te doen. Tevens moeten ze + aangeven wanneer het laad/save proces begint en eindigd. + + Neem als voorbeeld MoonBlaster. Het filemenu van dit + meesterwerk laat weinig te wensen over. Het is voor zowel + eencellige wezens, Stefan Boer en mensen overduidelijk + wanneer de computer bezig is met laden of saven. Het lampje + van de diskdrive knippert nl. uiterst vrolijk tijdens zo'n + aktie waarbij (samples buiten beschouwing gelaten) geen + verwarrende pauzes voorkomen. Dat laatste voorkomt + vroegtijdige eject neigingen. + + Een puntje van kritiek is wel dat MoonBlaster 'mislukte' + files niet delete bij bv. een disk full error. + + Abort en Retry opties tijdens een schrijfaktie mogen dus ook + wel. Het schrijfproces mag immers zonder het sluiten van de + file toch niet afgebroken worden en dus mag je de gebruiker + best de kans geven om de fout te herstellen. Dergelijke + opties zijn echter geen must. Een retry omdat iemand de disk + uit de drive haalt en deze daarna weer terug stopt zou + eigenlijk met een hatelijke "Blijf daar van af met je fikke" + sample beantwoord moeten worden en niet met het redelijk + beschaafde "Eh sorry, zal ik het nog eens proberen?". + + + T E C H N I S C H E D E T A I L S + + Even resumerend: + - Bij het laden van een file mag je van de gebruiker + verwachten dat hij van de eject knop af blijft. Doet hij + het toch, dan kan het geheugen corrupt raken, maar de disk + blijft tenminste heel. + - Bij het saven waarbij fouten optreden moet je niet gewoon + doen alsof je neus bloed, maar moet je netjes de rotzooi + opruimen. Zorg er m.b.v. je programma voor dat de + gebruiker niet in de verleiding komt om van diskette te + wisselen, zodat dit zo goed als altijd goed zal gaan. + + Het valt op dat het eigenlijk ontzetend vaak goed gaat. + Blijkbaar komt men niet zo snel op het idee om tijdens een + schijfaktie van disk te wisselen. Dit is dus blijkbaar niet + zo'n probleem. Er is echter een situatie denkbaar waarbij in + verhouding veel meer diskettes vernield raken. Stefan Boer + heeft deze situatie op Sunrise Special #1 ook al beschreven. + De situatie treedt op wanneer het cre�ren van een file + mislukt door een 'write protected' diskette. De gebruiker + stopt nu een nieuwe disk in de drive en drukt op (r)etry. + Deze nieuwe disk wordt nu vernield indien de error handler + verkeerd geschreven is. Hier is een (r)etry dus niet + ongevaarlijk! + + + ! ! ! B E L A N G R I J K ! ! ! + + + Een vroeger (ook door mij) sterk gepropageerde methode om + een retry uit te voeren in de BDOS error handler was door + register C=1 te maken, gevolgd door een RET instruktie. Dit + systeem werkt vaak goed, maar in de hierboven beschreven + situatie gaat het hopeloos fout. Het geval wil nl. dat de + FAT en directory sektor van de originele disk al in het + geheugen staan op het moment dat een "write protected" error + optreed. Na een (R)etry wordt echter niet meer gekeken of de + diskette gewisseld is. Tijdens het schrijven van de file + worden dus met hoge waarschijnlijkheid andere files + overschreven en na het sluiten van de file staat er + plotseling een verkeerde FAT en directory sektor op de + nieuwe disk. + + Samengevat: DOE NIET LD C,1 gevolgd door RET om een retry + optie te implementeren, maar doe het zoals de abort optie + werkt!!!! Herstel de stack en belangrijke registers zoals + ze voor de aanroep naar de BDOS waren en JP terug naar de + BDOS. Nu worden nl. eerst weer de FAT en directory van de + potentieel onbekende disk ingelezen. Ik heb dit geprobeerd + en het klopt als een bus. + + + C O N C L U S I E S + + Deze hele discussie over wat er nu precies moet gebeuren om + disk crashes te voorkomen loopt al een tijdje. Binnen + Sunrise leeft bij monde van Stefan Boer al geruime tijd de + overtuiging om diskakties bij foutsituaties zo snel mogelijk + af te breken (waarbij ik niet weet of hij adviseert ze eerst + te sluiten, maar dat zal wel), maar dat lijkt me dus alleen + maar gevaarlijker dan een keurige afhandeling. + + Kortom, neem aan dat de gebruiker niet gek is en handel een + schrijffout beschaafd af (sluiten en deleten). Zorg echter + wel voor een beetje transparantie van akties zodat + gebruikers niet in het ongewisse zijn over het feit wanneer + de diskaktie echt klaar is (lees: wanneer de file gesloten + is). Een tekstje "saving file..." op een statusbalk is bv. + een hele goeie. Verder MOET je er dus voor zorgen dat de + retry optie in de error handler goed ge�mplementeerd is. + + Op Sunrise Special #4 staat ook een listing van mijn hand + over diskerror afvanging onder DOS1 (en dus ook DOS2 + alhoewel deze eigen en betere routines heeft). Deze listing + werkt wel aardig en is leuk voor demo's en zo, maar het is + wat beperkt en de LD C,1 ; RET bug in de error handler zit + er ook in. Ik heb (met behulp van dit onderzoekje) de + routines nog eens dunnetjes over gedaan, waarbij vooral de + veiligheid van disk I/O prioriteit heeft gekregen. Affijn, + ik ben van mening dat deze nieuwe routines heel veel beter + en veiliger zijn dan de vorige en raad het gebruik van de + oude af. Lees echter ook de tekst op de volgende submenu + optie die wat uitgebreidere uitleg over de listing en + routines geeft. + + Ik vind het redelijk om van gebruikers het besef te vragen + dat ze zolang het disklampje brandt niet aan de ejectknop + moeten komen. Je kunt immers ook aan mensen vragen om bij + een rood verkeerslicht te wachten. Diegenen die dat niet + doen lopen dan het risiko om 5 liter rood lichaamsvocht aan + het ZOAB asfalt kwijt te raken, maar dat wisten ze + vantevoren. + + Alex van der Wal diff --git a/sunrise_special/7/Erix Driver.md b/sunrise_special/7/Erix Driver.md new file mode 100644 index 0000000..586d9b8 --- /dev/null +++ b/sunrise_special/7/Erix Driver.md @@ -0,0 +1,399 @@ + E R I X D R I V E R 1 / 2 + + + + W A A R O M E E N D R I V E R ? + + Het nut van een driver is het schrijven van toepassingen + voor RS232C, zonder dat je voor elke interface een apart + programma moet maken. Zo is het handig om een modem + programma wat je in combinatie met een SONY RS232C hebt + geschreven, deze door anderen gebruikt kan worden terwijl + die bv. een Philips NMS1210 hebben. + + + D E E I S E N A A N E E N D R I V E R + + Een driver moet aan verschillende eisen voldoen, wat die + eisen zijn ligt aan de toepassingen ervoor. + Ik ben toen een lijstje op gaan stellen van eisen die ik aan + een driver zou gaan stellen, de belangrijkste eisen staan + hieronder : + + - Driver moet functioneren onder MSX-DOS1 en MSX-DOS2, en + het liefst ook BASIC + - Driver voor verschillende typen interfaces moeten door + programma's gebruikt kunnen worden zonder speciale + aanpasssingen + - De driver moet snel zijn + - De driver moet resident blijven na installatie, zodat + het mogenlijk is van programma naar programma te + springen, zonder dat het nodig is om opnieuw de driver + in te laden. + + Er zijn al wel drivers die een aantal van deze eisen + bevatten, maar geen van allen doet dat ook werkelijk. + + Huib Walta had al een driver gemaakt die onder MemMan werkt, + maar die miste een van de eisen helemaal, en dat was + snelheid. MemMan is helaas niet snel genoeg om hoge + baudrates aan te kunnen. Dit komt doordat een MemMan TSR pas + aangeroepen wordt als een reeks interslot calls gebruikt + zijn. Aan de rest van de eisen wordt wel voldaan. + + De BASIC driver van Pier Feddema is ook goed, maar is helaas + alleen geschikt bij gebruik onder DISK-BASIC. De driver is + wel sneller dan de MemMan TSR die Huib Walta gemaakt heeft, + maar aangezien ik onder DOS wil werken voldoet ie voor mij + niet. + + Huib Walta heeft ook nog een driver gemaakt die onder + Turbo-Pascal werkt, maar deze driver is niet resident, en + zal elke keer vanuit DOS gelinked moeten worden aan je + programma. + + Toen ik geen drivers kon vinden die aan mijn eisen voldeden, + en ik toevallig genoeg informatie tegenkwam om de SONY + RS232C te kunnen aansturen, besloot ik om zelf dan maar een + driver te schrijven. + + + D E P R O B L E M E N V A N + E E N D R I V E R + + Toen ik begonnen was met het schrijven van een driver, kwam + ik meerdere problemen tegen..... + + Er moet een manier zijn om alle functies van de driver aan + te kunnen spreken, die voor alle drivers voor verschillende + interfaces hetzelfde is. Dit is simpel op te lossen door er + een JUMP-TABLE in te zetten, die door applicaties gebruikt + kan worden. + Als dit dan gerealiseerd is, moet de applicatie natuurlijk + ook weten of de driver er is, en zo ja, waar dan die + jump-table staat. + Om dit laatste te doen, heb ik iets gedaan wat eigenlijk + niet mag in de MSX standaard, ik heb een stukje in het + werkgeheugen gebruikt om daar 4 bytes te plaatsen. De eerste + twee bytes geven aan dat de driver er is, en de twee andere + bytes wijzen het adres aan waar de jump-table in het + geheugen staat. De driver kan alleen van disk worden + geladen, dit omdat de driver een aparte loader nodig heeft + die een file van DISK wil laden. Daarom heb ik gekozen om + deze informatie op te slaan in het cassette-parameter table, + op adres &HF3FC. Cassette wordt toch meestal niet gebruikt + als er een diskdrive aanhangt, en de RS232C gebruikt gaat + worden. + Om effectief met het geheugen om te gaan is het noodzakelijk + dat de driver zo hoog mogenlijk in het geheugen komt te + staan, het liefst hoger dan dat MSXDOS.SYS zich nestelt, + zodat er naar BASIC, en weer naar DOS gegaan kan worden, + zonder dat de driver aangetast wordt. + Doordat de top van het geheugen niet vast gedefinieerd is, + is het noodzakelijk dat de driver op elk adres kan werken. + Aangezien het praktisch onmogenlijk is om de driver in + mekaar te zetten, met alleen relatieve adressen, is het + noodzakelijk dat de driver zichzelf eenmalig aan kan passen + aan een bepaald adres in het geheugen. Hiervoor is de driver + gemaakt alsof ie van adres 0 werkt. En bij de driver is een + tabel geplaatst met informatie over wat er in de driver + veranderd moet worden. Dit aanpassen wordt door een + speciale loader gedaan. + Nog een groot probleem van een driver is dat ie resident + moet zijn. Een driver inladen en die informatie op &HF3FC + te plaatsen is niet moeilijk, nu moet alleen gezorgt worden + dat de driver intact blijft als MSX-DOS in werking komt. Dit + blijkt niet erg moeilijk te zijn, het is simpel om HiMem aan + te passen, en je driver daar net boven te plaatsen. Het + nadeel is echter dat MSX-DOS dit niet slikt, en je deze + methode vanuit BASIC moet gebruiken. Een methode is om de + driver te laden vanuit BASIC, maar aangezien ik met MSX-DOS + werk heb ik gekozen om een loader de driver in te laten + laden, de driver op het juiste adres neer plaatsen, naar + BASIC toe te gaan, wat informatie in het werkgebied + aanpassen, en dan verdergaan. + Om het mogenlijk te maken dat er automatisch nog wat gedaan + wordt nadat de driver ingeladen is, is het mogenlijk om de + driver als het ware zelf de commando's te laten intikken. + Dit is heel simpel te maken door een string naar de + toetsenbord buffer te kopieren, wat pointers aanpassen, en + BASIC de controle over laten nemen. + + Nu bleef ik nog zitten met de snelheid van de driver. + Zoals bij meesten wel bekend, genereert een RS232C interface + een interrupt als er data binnenkomt. Door snel op deze + interrupt te reageren heb je het IC wat de data verwerkt + uitgelezen voordat er nieuwe data binnenkomt die deze + informatie overschrijft. + Zodra er een interrupt optreed, zorgt de Z80 ervoor dat er + automatisch een CALL uitgevoerd wordt naar adres &H0038, op + die adres staat een jump naar een ander adres waar een + routine staat wat netjes zorgt dat &HFD9A aangeroepen wordt, + even kijkt of de interrupt van de VDP is (50/60 Hz) en zo + ja, dan even &HFD9F aanroept. In deze routine wordt ook o.a. + het toetsenbord afgescanned, wat tellers bijgehouden, en nog + meer onzin. Dit alles zorgt ervoor dat deze routine + behoorlijk lastig is als er op hoge snelheid data + binnenkomt, waardoor er data verloren gaat. + Wat dit ook inhoud, is dat er minder processor tijd + overblijft om de data die ontvangen is te verwerken. Dit + houd in dat het onder BASIC bij 19200 baud zo'n beetje + ophoud als je een normale Z80 op 3.58 Mhz gebruikt. + Onder MSX-DOS is dit nog erger, als er een interrupt optreed + wordt er naar &H0038 gesprongen, vanuit hier wordt er weer + ergens anders hoog in het geheugen gesprongen, vanwaaruit + een interslot call gedaan wordt naar de BIOS ROM op adres + &H0038. Dit alles verziekt de boel zo, dat het ontvangen van + data op hoge snelheid haast onmogenlijk wordt gemaakt. + Dit is onder MSX-DOS aanzienlijk te versnellen door in het + RAM deze jump aan te passen, zodat er als er een interrupt + optreed, de driver het eerst aan bod komt. Ook het ik de + driver zo gemaakt, dat als de interrupt voor de driver + bestemd was, deze dan niet meer door het BIOS gebruikt + bekeken wordt, of eventueel het BIOS niet meer aan te laten + roepen, om zo de maximale snelheid eruit te halen. De + methode van interrupt gebruik is in te stellen, dit om zelf + te kunnen kiezen voor keyboard gebruiken of niet, want dat + is wel de consequentie hiervan. + + (vervolg, zie text 2) + + + + E R I X D R I V E R 2 / 2 + + + + S P E C I F I C A T I E S + + Controleren op aanwezigheid driver : + + Kijk of er op adres &HF3FC/&HF3FD "RS" staat, zo ja, dan + is de driver aanwezig, ander niet. + + Pointer naar jump tabel : + + Als de driver geinstalleerd is, staat er op &HF3FE een + pointer naar de jump tabel, deze tabel is momenteel 63 + bytes lang. (21 jump entry's) + Deze pointer heeft LSB op &HF3FE en het MSB op &HF3FF + + Functies : + + Offset Functie Uitleg + +0 GetVersion Geeft het versie nummer van de driver + in HL terug. [H] = main version, + [L] = sub versie, beide packed BCD + +3 Init Initialiseert de functies van de UART, + zorgt dat data ontvangen/verzonden kan + worden. + +6 DeInit Zet de driver op non-actief + Dit moet gedaan worden als de driver + niet meer gebruikt wordt, dit ivm. een + vervelende eigenschap van de Philips + NMS121x serie, die de UART niet reset + als je de computer reset. Als deze + functie dan niet gebruikt is, is het + mogenlijk dat de computer gaat hangen + als er data binnenkomt. + +9 SetBaud Stelt de baud-rate in + [H] = Transfer, [L] = Receive rate + Nadat de snelheid ingesteld is, komt + de daadwerkelijk ingestelde baudrate + weer terug in [H] en [L], dit om te + kontroleren of die gekozen snelheid + wel ingesteld kan worden. + De baud rate wordt aangegeven door een + index, hieronder een lijstje... + + Index Baudrate + 0 75 + 1 300 + 2 600 + 3 1200 + 4 2400 + 5 4800 + 6 9600 + 7 19200 + 8 38400 + 9 57600 + 10 76800 + 11 115200 + Index 8 en hoger zijn niet bruikbaar + op een SONY interface + + +12 Protocol Stelt het protocol in waarmee de + RS232C werkt + [H] Bit 0,1 is het aantal databits + 00 = 5 bits + 01 = 6 bits + 10 = 7 bits + 11 = 8 bits + Bit 2,3 is het aantal stopbits + 01 = 1 stopbit + 10 = 1.5 stopbit + 11 = 2 stopbits + Bit 4,5 stelt de parity in + 00 = none + 01 = even + 11 = oneven + Bit 6,7 van [H] moeten op nul staan, + en register [L] moet ook op nul staan, + dit voor toekomstige uitbreidingen. + +15 Channel Stel kanaal [H] in + Als je een multi-channel interface + hebt (zoals de NMS1211), kun je + hiermee instellen welk kanaal je + gebruikt. + De kanalen niet gebruikt worden met + DeInit behandeld, en bij het kanaal + wat je insteld wordt een Init + uitgevoerd. + +18 RS_In Geef ontvangen data terug in [A] + De data wordt uit een ontvangstbuffer + gelezen die momenteel 512 bytes groot + is. + Als er geen data beschikbaar is staat + is [A]=0, om te weten of er data is, + kun je RS_In_Stat gebruiken. + +21 RS_Out Stuur [A] naar de RS232C + Deze routine keert pas terug als de + data verzonden is, deze zal dus + blijven wachten als de tegenpartij RTS + laag heeft gemaakt! + Om te weten of je wel mag zenden kun + je RS_Out_Stat gebruiken. + +24 RS_In_Stat Geeft in [A] terug of er data + beschikbaar is of niet. + [A] = 0 Geen data in buffer + [A] <> 0 Data aanwezig in buffer + +27 RS_Out_Stat Geeft in [A] terug of er data + verzonden mag worden. + [A] = 0 Data mag niet verzonden + worden + [A] <> 0 Data mag verzonden worden + + +30 DTR Stelt DTR in (Data terminal ready) + [H] = 0 maak DTR laag + [H] = 255 maak DTR hoog + +33 RTS Stelt RTS in (Request to send) + [H] = 0 maak RTS laag + [H] = 255 maak RTS hoog + +36 Carrier Geeft de huidige carrier status terug + in [A] + [A] = 0 Geen carrier + [A] <> 0 Carrier aanwezig + +39 Chars_In_Buf Geeft in HL het aantal bytes dat in + de ontvangstbuffer zit + +42 Size_Of_Buf Geeft in HL de grootte van de + ontvangst buffer + +45 FlushBuf Maakt de ontvangstbuffer leeg + +48 FastInt Zorgt ervoor dat de hook op &H0038 + afgebogen wordt, of hersteld wordt. + Deze routine controleerd zelf of de + hook al of niet afgebogen is, om + dubbel installeren/herstellen te + voorkomen. + [H] = 0 Zorgt voor normale interrupt + verwerking + [H] = 1 Zorgt dat de interrupts veel + sneller afgehandeld worden. + Door eerst met [H]=0 FastInt aan te + roepen, een andere int. handler op + &H0038 te installeren, en uiteindelijk + weer met [H]=1 FastInt aan te roepen, + is het mogenlijk om nog een andere + interrupt handler actief te hebben + tegelijkertijd met de RS232C driver. + Deze methode kan, indien goed gedaan, + enorm veel snelheidswinst opleveren. + Je kunt zo bv. een keyboard handler + installeren, en het BIOS helemaal + buiten spel zetten! + +51 Hook38Stat Stel in of normale BIOS interrupts (of + de oude interrupt handler die op + &H0038 stond) nog ondersteund dienen + te worden. (Om nog meer winst te + krijgen wat betreft processortijd) + Worden "normale" interrupt afgezet, + dan wordt er nog wel gezorgd dat + systeemvariabele JIFFY blijft lopen! + [H] = 0 "normale" interrupts + [H] <> 0 Alleen RS232C interrupts + Deze functie werkt alleen als FastInt + aangeroepen is met [H]=1 + +54 ChPut_Hook Stelt in of schermuitvoer via ChPut + ook naar de RS232C verzonden dient te + worden. + [H] = 0 Geen uitvoer naar RS232C + [H] = 1 Alle uitvoer naar RS232C + [H] = 2 Zie 1, maar nu zonder deze + text op het scherm te zien. + Levert snelheidswinst op. + +57 Keyb_Hook Stelt in of binnenkomende data naar de + ontvangstbuffer moet, of in de + keyboard buffer moet worden gezet. + [H] = 0 Data naar ontvangstbuffer + [H] = 1 Data naar keyboard + +60 Get_Info Geeft in HL een pointer naar een tabel + met informatie over de driver. + + DRIVER INFO BLOCK + + Offset Bytes Description + +0 2 Versie nummer +1 bevat het hoofd nummer + +0 bevat een sub-versie, allebij Packed BCD + +2 1 Huidige ontvangs snelheid (index) + +3 1 Huidige zend snelheid (index) + +4 1 Huidig protocol + bit 0-1 Data Bits + 00 5 bits + 01 6 bits + 10 7 bits + 11 8 bits + 2-3 Stop Bits + 01 1 stopbit + 10 1.5 stopbits + 11 2 stopbits + 4-5 Parity + 00 geen + 01 even + 11 oneven + 6-7 0 niet gedefinieerd + +5 1 ChPut_Hook status + +6 1 Keyboard_Hook status + +7 1 Huidige RTS status + +8 1 Huidige DTR status + +9 1 Huidig kanaal + +10 1 Hardware info + 0 = Geen informatie + 1 = ASCII monochannel compatible + 2 = NMS121x interface (multichannel) + 3!= MT-Telcom, aangepast voor RS232C + 4!= NMS1250, aangepast voor RS232C + 5!= Gradiente interface (brazilie) + 6!= Multichannel ASCII compatible + Versies met een "!" zijn nog niet gemaakt, maar + er is een kans dat dezen er nog zullen komen. + + + L A A T S T E O P M E R K I N G E N + + Deze driver is nog niet compleet uitontwikkeld, dus er + zullen nog wel uitbreidingen komen. Deze uitbreidingen + zullen compatible blijven met oudere versies van de driver. + Ik ben bezig met een terminal te schrijven voor deze driver, + genaamd ERIX, deze heeft minimaal een MSX2 nodig met 64 Kb, + en minimaal MSX-DOS1. ERIX ondersteund Xmodem(1k) en Ymodem, + zowel up/download. De schermuitvoer is behoorlijk snel, en + emuleert momenteel VT-52, ANSI wordt nog gemaakt. + De driver heeft geen bezwaar tegen een turbo-R op R800-Dram + mode, maar werkt natuurlijk ook goed op een 3.58 Mhz Z80. + Om steeds de nieuwste versie van ERIX en de drivers te + bemachtigen, kun je naar The Games BBS (04120-40358) bellen, + en daar de nieuwste versies te zoeken. + Als je nog aan- en/of opmerkingen hebt, laat dan een + berichtje voor me achter in MSX-net (inlogpunt bv. + RoefSoft), of stuur een berichtje naar me in The Games BBS. + Gewoon onder de naam : + Erik Maas diff --git a/sunrise_special/7/Gestructureerd ML deel 3.md b/sunrise_special/7/Gestructureerd ML deel 3.md new file mode 100644 index 0000000..3f4a1b6 --- /dev/null +++ b/sunrise_special/7/Gestructureerd ML deel 3.md @@ -0,0 +1,129 @@ + G E S T R U C T U R E E R D M L ( 3 ) + + + Een kort deel deze keer, zoveel valt er nu ook weer niet + over dit onderwerp te vertellen zonder op details in te + gaan, en daar hebben we al de rubriek ML technieken. + + Het is een beetje afhankelijk van het project waar je mee + bezig bent, maar zelf geef ik duidelijk programmeren + voorrang boven een paar bytes minder code of een paar + klokpulsen minder. Wat ik bedoel is: als ik kan kiezen + tussen een duidelijke oplossing van 10 bytes en 30 + klokpulsen en een minder duidelijke oplossing van 8 bytes en + 25 klokpulsen, dan zal ik toch de duidelijke oplossing + kiezen. Als ik om snelheids- of ruimteredenen toch de minder + duidelijke oplossing moet kiezen, zal ik extra commentaar + erbij zetten. + + Even een paar voorbeelden. Als er aan het eind van een + routine het volgende staat: + + CALL AndereRoutine + RET + + Scheelt het 1 byte en 18 klokpulsen om dit te vervangen door + + JP AndereRoutine + + Dit is echter niet het meest duidelijk, want het einde van + een routine is RET en niet JP. Nog een voorbeeld: + + CP #FF + JR Z,Label + + Hier kan de CP #FF worden vervangen door een INC A. Dat + scheelt 1 byte en 3 klokpulsen. Maar het is veel + onduidelijker, we willen immers kijken of A gelijk is aan + #FF en we willen A helemaal niet verhogen. (De CP #FF kan + dan ook niet door INC A worden vervangen als je de waarde + van A daarna nog nodig hebt.) Als je dit toch gebruikt omdat + je zeer krap zit qua tijd en/of geheugen, doe het dan zo: + + INC A ; CP #FF + JR Z,Label + + Zo kun je in ieder geval nog aan het commentaar zien wat de + bedoeling was. Zelf gebruik ik wel AND A in plaats van CP 0, + maar dat is iets anders omdat AND A alleen die betekenis + heeft (tenminste voor mij), terwijl je INC A ook heel vaak + gebruikt om gewoon A te verhogen. De carry wissen doe ik + trouwens met OR A. Dat kan ook met SCF; CCF maar dat is veel + langzamer en neemt meer bytes in beslag. AND A zou ook + kunnen, maar ik heb met mezelf afgesproken dat ik AND A + gebruik voor CP 0 en OR A om de carry te wissen. Zo kan ik + ��n oogopslag zien wat een instructie betekent. + + + J R O F J P ? + + JP is sneller dan JR maar neemt ��n byte meer in beslag. + Bovendien is een voorwaardelijke JR sneller als er niet + wordt gesprongen. Wanneer gebruik je JR en wanneer JP? + + Ik gebruik zoveel mogelijk JR voor sprongen binnen ��n + routine. Zo kun je meteen zien dat het een sprong binnen + dezelfde routine is. Soms kan dat niet omdat de + sprongafstand te groot is, maar dat is vaak een teken dat de + routine te lang is en in deelproblemen moet worden + opgesplitst. Dit is echter zeker geen wet van meden en + perzen. JP is bij mij gereserveerd voor sprongen naar een + andere routine, al moet je dat alleen in speciale gevallen + doen. Want voor dat je het weet heb je een onleesbaar stuk + spaghetti. Verder ondersteunt JP meer voorwaardelijke + sprongen (P, M, PE, PO) dan JR, maar die gebruik je vrij + weinig. + + Voor degenen die in tijd- of ruimtenood zitten nog even de + gegevens van JP en JR: + + klokcycli: bytes: + + JP 11 3 + JR 13 (8) 2 + + De tijd tussen haakjes bij JR geeft aan hoe lang het duurt + als er niet wordt gesprongen bij een voorwaardelijke sprong. + Het is overigens logisch dat JR langer duurt dan JP, omdat + bij JP de Program Counter gewoon met het adres geladen kan + worden, terwijl bij JR iets bij de Program Counter moet + worden opgeteld. + + + N O G Z O I E T S + + Stel je wilt wachten tot bit 0 van I/O poort #65 laag wordt + (wachten op CE bij V9990). Dan programmeer ik dat zo: + + WaitCE: IN A,(#65) + BIT 0,A + JR NZ,WaitCE + + Zo kun je precies zien wat er gebeurt. Ik geef toe dat het + sneller is om onderstaande variant te gebruiken, maar hier + is het minder duidelijk: + + WaitCE: IN A,(#65) + RRCA + JR C,WaitCE + + Bit 0 wordt namelijk in de carry geschoven door RRCA. Als je + dat er in commentaar achter zet is het natuurlijk al weer + een stuk duidelijker. Het nadeel van deze methode is dat het + alleen bij bit 0 werkt, bij een ander bit moet je toch weer + op BIT n,x terugvallen. + + + S N E L H E I D O F N E T H E I D ? + + Nogmaals, het hangt af van het soort programma hoeveel + aandacht je aan de netheid KUNT besteden. Want als je het + onderste uit de kast wilt halen dan kan dat alleen maar door + een tabel met klokcycli bij de hand te houden en overal de + snelste oplossing voor te kiezen. Maar bij veel programma's + is dat onzin en dan is het belangrijker om de netheid in het + hoog te houden, zodat je eigen sources straks tenminste nog + kunt begrijpen. Gebruik in ieder geval commentaar bij + truukjes die je niet al veel vaker hebt gebruikt. + + Stefan Boer diff --git a/sunrise_special/7/Harddisks op MSX.md b/sunrise_special/7/Harddisks op MSX.md new file mode 100644 index 0000000..defe01f --- /dev/null +++ b/sunrise_special/7/Harddisks op MSX.md @@ -0,0 +1,336 @@ + H A R D D I S K S O P M S X + + + + D E M O G E L I J K H E D E N + + Al in 1990 was de eerste harddisk interface voor MSX + verkrijgbaar. Tot nu toe is er niet veel aandacht besteed + aan MSX harddisks. Dit is voor verandering vatbaar, nu + steeds meer mensen het genot van een harddisk aan de MSX + ervaren. + + MSX is lang verstoken gebleven van harddisks. Philips is wel + al heel lang geleden bezig geweest met een SCSI interface + voor MSX, maar die is nooit uitgekomen. Tot 1990 heeft het + moeten duren voor de eerste interface voor het gewone + publiek te krijgen was. Althans, voor mensen met genoeg + geld! De eerste complete harddisks waren vrij prijzig. + + In een paar jaar is dat echter grondig veranderd. De prijzen + van SCSI interfaces voor MSX zijn een stuk redelijker + geworden, en bovenal, SCSI harddisks zelf zijn een stuk + goedkoper geworden! Dit is voornamelijk te danken aan het + feit dat mensen met andere computers, zoals Apple en Atari, + overstapten op HD's met een veel grotere inhoud. Een 40 MB + HD kost nu toch al gauw minder dan 200 gulden op de + tweedehandsmarkt. + + + D E I N T E R F A C E S + + De eerste interface was van HSH. Deze interface is de enige + die ook onder MSX-DOS1 werkt. Het nut hiervan is echter niet + al te groot. Het werken met subdirectory's is echt een + vereiste voor een HD-gebruiker. + + De HSH interface kan 6 partities (zie verderop) aan, en + beschikt over netwerkmogelijkheden. + + Toen kreeg ook MK een vinger in de HD-pap. MK bracht een + interface op de markt met de mogelijkheid om 4 partities aan + te sturen, die ook weer de mogelijkheid had met SCSI + netwerken om te gaan. + + + G O U D A 'S G L O R I E + + Van MAK of Green komt de interface die later door MSX Club + Gouda geadopteerd is. Deze kan 4 partities gebruiken, en + bezit geen netwerkmogelijkheden. + + Sinds begin dit jaar is er echter een nieuwe Gouda interface + leverbaar. Het gaat hierbij om een flink verbeterd HSH + ontwerp. De interface heeft netwerkmogelijkheden, en op een + turbo R is het ding supersnel! + + + P A R T I T I E S + + Al een aantal malen heb ik het woord "partitie" gebruikt. + Als een HD 4 partities heeft, betekent dit dat de HD voor de + computer uit 4 drives bestaat: A:, B:, C: en D:. Omdat een + drive maximaal 32 MB kan zijn, kan een interface met 4 + partities dus ook ten hoogste 128 MB aansturen! + + Het gebruik van 6 partities is niet zo handig, omdat je + meestal minstens over EEN drive en een RAMdisk wilt + beschikken. Een beperking van DOS2 is dat je maar 8 drives + kunt gebruiken. Ook een beperking is dat je geen RAMdisk + kunt aanmaken als je al 8 drives hebt. In het geval van 6 + partities en 2 drives (ook een virtueel drive telt mee + zijn), kun je dus geen RAMdisk meer aanmaken. + + + H A R D D I S K Z E L F + + Voordat je de aanschaf van een bepaalde harddisk overweegt, + is het belangrijk even na te denken over wat je erop gaat + zetten. Als je heel veel plaatjes, spellen en muziek erop + gaat zetten, is 100 MB wel handig. + + Als je echter zuinig met de ruimte omgaat, en alleen echt + handige dingen op je HD wilt zetten, is 20 MB al meer dan + genoeg. + + Voor de meeste MSX'ers zal een harddisk tussen de 30 en 40 + MB wel voldoende zijn. Alles samen moet in dat geval wel + voor 400 gulden te verkrijgen zijn. Ongeveer � 200,- voor de + harddisk, � 150,- voor de interface en � 50,- voor voeding, + kastje en kabels. [Nvdr. Als je een turbo R hebt is de + aanschaf van een HG-interface voor � 239,- zonder meer het + geld waard.] + + + H D I N D E L E N + + Als je in het bezit bent van je harddisk, is het belangrijk + om niet gewoon alles wat je hebt erop te gooien - oftewel + kopi�ren - maar een beetje overdacht te werk te gaan. Dit om + ervoor te zorgen dat je na een tijdje door de bomen het bos + niet meer ziet, en om de haverklap utility's als FileFind + nodig hebt om een bepaalde file uit een wirwar van + subdirectory's terug te vinden. + + + N O G M A A L S : P A R T I T I E S + + Om maar te beginnen bij het begin: je moet de harddisk + opdelen in partities. Dit wordt ook wel "high level + formatteren" genoemd. Meestal is de harddisk al "low level" + geformatteerd. + + Bij het low level formatteren wordt de disk echt + leeggemaakt. Dit neemt dan ook veel tijd in beslag. High + level formatteren houdt het indelen van de HD in partities + in, en het daarbij opgeven van bepaalde belangrijke + gegevens, zoals de FAT-grootte, de grootte van de + rootdirectory, etc. + + + C L U S T E R G R O O T T E + + Je kunt, als je een harddisk kleiner dan of gelijk aan 32 MB + hebt, gewoon ��n partitie aanmaken. Maar dit is niet erg + slim. Je krijgt dan vrij grote clusters, soms zelfs van 32 + kB. Hierdoor wordt je harddisk niet erg snel, en is hij ook + vrij snel gevuld. + + Een programmaatje van 10 bytes kost bij een clustergrootte + van 32 kB nl. 32 kB! Bij clusters van 1 kB echter nog maar 1 + kB. + + Het is dus verstandig om een kleine A: partitie aan te maken + met daarop allerlei (kleine) programma's die je vaak + gebruikt. Ik heb zelf gekozen voor 4 MB. Als je dan de FAT + op 12 sectoren zet, heb je clusters van 1 kB. + + + F A T - G R O O T T E + + Je kunt het beste altijd een FAT van 12 sectoren nemen, dan + is de clustergrootte het kleinst. + + Nu de eerste partitie klein is, kun je de volgende + partitie(s) natuurlijk wel zo groot mogelijk maken. Als je + het �cht maximaal neemt, krijg je clusters van minimaal 32 + kB. Ik heb daarom even gekeken of dit niet beter kon. En het + KON beter. Als je als grootte 32686 kB neemt (bij FDISK van + MK), krijg je met een FAT van 12 sectoren clusters van 16 + kB, en bij 1 kB meer is dit al 32 kB. [Nvdr. Bij de HG + interface krijg je maximaal clusters van 8 kB.] + + + R O O T - D I R + + Je moet voorkomen dat er veel files in de rootdirectory + komen te staan. Je kunt het beste alleen COMMAND2.COM, + MSXDOS2.SYS, AUTOEXEC.BAT en REBOOT.BAT in de root laten + staan. Dit is niet alleen voor de overzichtelijkheid, maar + het komt ook de snelheid ten goede. Bij het opstarten worden + de juiste files dan meteen gevonden. + + De rootdirs van de andere partities kun je het beste + helemaal leeg laten. Daar mogen eigenlijk alleen maar + subdirectory's in staan. + + Bij FDISK kun je daarom ook het beste de dirgrootte op 64 + bestanden zetten, omdat dit de kleinste grootte is. + + + S U B D I R S + + Zoals gezegd komen op A: programma's die vaak gebruikt + worden. Ik heb zelf gekozen voor de volgende indeling van A: + + A:\ + 2RAMDISK + BATCH + MEMMAN + TSRS + UTILS + BASIC + CRUNCH + DOS2TOOL + ML + TURBOR + + In 2RAMDISK staan vaakgebruikte programma's die door + AUTOEXEC.BAT naar de RAMdisk gekopieerd worden. (Na een + reset wordt mijn RAMdisk gered door RRAMDISK, dus dit kost + alleen tijd als ik de computer aanzet.) + + BATCH bevat alle batchfiles die ik gebruik, MEMMAN allerlei + MemMan files, TSRS alle MemMan TSR's, en UTILS en zijn + subdirectory's alle verdere utility's. + + Voor de verdere indeling van UTILS heb ik gekozen om + bepaalde utility's nog enigszins makkelijk terug te kunnen + vinden. + + Wat allemaal op mijn andere 3 partities staat is verder niet + zo heel interessant. Maar misschien wel belangrijk is de tip + om ervoor te zorgen dat de rootdirectory niet al te vol + wordt gezet met subdirectory's. + + Als je werkt met algemene directory's, komt dat de + overzichtelijkheid zeker niet ten slechte. Ik heb zelf zo + subdirectory's met namen als MUSIC, TEKST en PROG. Deze + directory's bevatten zelf geen enkele file, maar slechts + subdirs. + + + H A R D D I S K U T I L S + + Voor harddiskgebruik zijn er gelukkig al een aantal + utility's gemaakt. Zo bestaat het programma FileFind, zelfs + in drie verschillende versies. Maar die van Ramon van der + Winkel is wel het beste - d.w.z. snelste en kleinste. Dit + programma staat op de disk. + + + T O + + Zodra je harddisk een beetje vol begint te raken, kost het + veranderen van directory al snel redelijk wat typewerk. + Gelukkig is hiervoor een oplossing. + + De meeste PC'ers kennen het programmaatje TO al, eventueel + onder de naam NCD (Norton Change Dir). Daar werkt het echter + wel iets iets anders. TO UT, bijvoorbeeld, geeft een + overzicht van alle subdirectory's die het stukje "UT" in de + naam hebben zitten. Bij mij staan er dan onder andere UTILS + en OUTDOOR bij. + + TO is een public domain programmaatje van C.P.U. dat ook op + deze disk te vinden is. + + Bij TO UT komt het volgende op mijn scherm: + + A - A:\MEMMAN\TSRS + B - C:\DIVERSEN\FONTS + C - D:\TEMP\KIER\BACKATSU + + Als ik dan op A druk, wordt er meteen naar de directory + A:\MEMMAN\TSRS gesprongen. + + Voordat TO kan werken moet het echter eerst een overzicht + aanmaken van alle subdirectory's - telkens alle dirs + opzoeken zou veel te traag gaan. Met het environment item + TO_PATH geef je aan waar dit overzicht komt te staan. Met de + optie /S (scan) achter TO geef je aan dat er een overzicht + moet worden aangemaakt, dat onder de naam TO.LST in de door + TO_PATH aangeduide dir komt te staan. + + + M E E R D E R E D R I V E S + + TO kan ook met meerdere drives werken. Gelukkig wel, anders + moest je nog steeds weten op welke drive de bepaalde dir + staat. Het environment item TO_DRIVES geeft aan welke drives + gebruikt worden door TO. Zo bevat mijn AUTOEXEC.BAT het + commando "SET TO_DRIVES=ABCD". + + Als je er iets aan de samenstelling van de subdirectory's + verandert, zou je eigenlijk weer opnieuw moeten scannen. + Gelukkig heeft Fokke Post (de maker) hier rekening mee + gehouden. De volgende opties zijn hiervoor bedoeld: + + /M : Maakt een nieuwe directory aan. Komt overeen met MKDIR + of MD. + /D : Wist de directory. Komt overeen met RD of RMDIR. + /C : Maakt een nieuwe directory aan, en ga er gelijk + naartoe. Dus eigenlijk zijn twee commando's + samengevoegd: MD en CD: MCD! + /R : Hernoemt een directory. Staat gelijk met RNDIR. + /V : Verplaatst een hele directory naar (in) een andere + directory. Hiervoor had COMMAND2.COM nog geen commando, + maar MVDIR zou het wel geheten hebben. + + + C O M M A N D 2 A A N P A S S E N + + Bij TO v1.52 zat een programmaatje INSTALL.COM dat o.a. + COMMAND2.COM kan aanpassen. Dan worden de commando's die + beter via TO gedaan kunnen worden verwijderd uit het + vocabulaire van COMMAND2 (MD, CD, RNDIR enz.). Deze + commando's worden dan vervangen door batchfiles. + + Dit is heel handig, maar het is jammer dat het mijn + COMMAND2.COM helemaal verneukte - excusez le mot. Ik heb + toen met een foefje (opstarten met HD aan, als computer + zoekt naar MSXDOS2.SYS HD uitzetten, en even later weer + aanzetten) COMMAND2.COM weer moeten kopi�ren van een gewone + disk. + + Gelukkig is de programmeur op de hoogte gesteld, en bevat + bestaat er nu een prima werkende INSTALL. De moraal van dit + verhaal is echter: probeer vitale bestanden (eigenlijk + alleen COMMAND2.COM en MSXDOS2.SYS) eerst uit op gewone + diskettes of op de RAMdisk voordat je ze kopieert naar de + harddisk. + + [Nvdr. Het is het verstandigste om op de A: partitie alleen + utility's en dergelijke te zetten die je ook op disk heb + staan, dus geen eigen teksten, sources etc. Want in het + geval de A: partitie echt verrot raakt (bijvoorbeeld dat + MSXDOS2.SYS of COMMAND2.COM vastslaat), is de enige + oplossing om weer in je HD te komen de A: partitie opnieuw + installeren, en dan ben je alles kwijt wat erin stond. Dat + is met utility's die je zo weer van disk kunt kopi�ren geen + probleem, maar met sources, teksten etc. waarvan je geen + backup hebt een ramp! Ik spreek uit ervaring, maar bij mij + liep het gelukkig nog net goed af.] + + + V E R D E R E F U N C T I E S + + TO kan ook nog heel snel terugspringen in directory's. TO .. + werkt hetzelfde als CD .., maar TO kan ook nog meer puntjes + verwerken. Drie puntjes betekent twee directory's terug, + enz.. Met TO -5 ga je echter ook meteen 5 directory's terug + (staat dus gelijk aan ......). + + Bij het aanmaken en springen naar directory's kun je overal + de optie /H gebruiken om hidden directory's te nemen. + + Met de optie /N kun je aanduiden dat TO gewoon de directory + moet nemen die hij het eerste vindt. Zo kun je lijsten van 3 + schermen (bijv. bij TO S) voorkomen. + + Van dezelfde programmeur komt ook het programmaatje + TREE.COM. Hiermee kun je een overzicht van de directory's + van een bepaalde drive krijgen. Het werkt natuurlijk met de + door TO.COM aangemaakte file TO.LST. + + Kasper Souren diff --git a/sunrise_special/7/Interfacing RS232.md b/sunrise_special/7/Interfacing RS232.md new file mode 100644 index 0000000..8693fa8 --- /dev/null +++ b/sunrise_special/7/Interfacing RS232.md @@ -0,0 +1,188 @@ + I N T E R F A C I N G ( R S 2 3 2 C ) + + + + W A A R O M E E N S T A N D A A R D ? + + Om goede interfacing te kunnen doen, dwz. data uit + wissellen, is het noodzakelijk dat de verschillende systemen + die dat moeten kunnen doen compatible zijn. Hiervoor zijn + afspraken nodig. + + Deze afspraken houden het volgende in : + - Hoe moet de verbinding gerealiseerd worden? + - Wat betekenen deze verbindingen? + - Wat zijn de defenities van de signalen die deze + verbindingen voeren? + + + W I E M A A K T D E A F S P R A K E N ? + + De afspraken die we nu gebruiken met de RS232C gedefinieerd + door EIA (Electronic Industries Association) zijn afgeleid + van de V.24 en V.28 aanbeveling van het CCITT (Committee + Consultative International de Telegraphique et + Telephonique), een organisatie die standariserings normen + vaststeld. V.24 worden de functies van de pennen + gedefinieerd, terwijl V.28 de spanningsnivo's definieren. + + + W A T I S V . 2 8 ? + + Om data over een draad te kunnen verplaatsen, hebben we + duidelijke afspraken nodig over de nivo's. Zo hoeven we met + de computer maar een "0" of een "1" over de lijn te krijgen, + of in geval van controle signalen een "on"/"off". + Nu is de afspraak gemaakt dat met een negatieve spanning we + een "1" hebben, of in het geval van een control signaal een + "off". De maximale spanningen die gebruikt mogen worden zijn + -25 en +25 Volt. Het gebied tussen -3 en +3 Volt is niet + gedefinieerd. + Dus zenden we een "1"(off) over, dan moet de spanning tussen + -25 en -3 Volt liggen. + De reden dat het gebied tussen -3 en +3 volt niet + gedefinieerd is, ligt aan het feit dat je hardware nodig + hebt die de lijn meet, om die hardware simpel te kunnen + houden, moeten we een hogere spanning sturen dan in feite + nodig is. + Meestal wordt met -12 en +12 gestuurd. + + + W A T I S V . 2 4 ? + + Deze afspraken houden in wat de functies van diverse + signalen zijn. + + Hieronder een overzicht van de defenities van de pinnen bij + een 25 pin's sub-D aansluiting. (Die op de meeste RS232C + interfaces zit) + + Type Pin MNEMONIC Uitleg In/Out + + GROUND 7 GND Ground - + + DATA 2 TMD,TxD TransMit Data O + 3 RCD,RxD ReCeive Data I + + CONTROL 4 RTS Ready To Send O + and 5 RFS,CTS Clear To Send I + STATUS 6 DSR Data Set Ready I + 20 DTR Data Terminal Ready O + 8 DCD Data Carrier Detect I + 23 DRS Data Signal rate Selector O + 22 CIN Calling Indicatior I + 11 STF Select Transmit Frequency O + + CLOCK 24 TSET,TxC Transmitter Signal Element Timing O + 15 TSET,TxC Transmitter Signal Element Timing I + 17 RSET,RxC Receiver Signal Element Timing I + + BACK- 14 TMD,TxD TransMit backward channel Data O + WARD 16 RCD,RxD ReCeive backward channel Data I + CHANNEL 19 RTS Ready To Send backward channel O + 13 RFS,CTS Clear To Send backward channel I + 12 DCD backward channel DCD I + + TEST 21 RIL Loopback test O + 18 LL Local Loopback O + 25 TI Test Indicator I + + + U I T L E G S I G N A L E N + + D A T A + + Via TMD wordt de data verzonden, de data moet serieel + verstuurd worden, dit heeft als voordeel dat we maar 1 + lijn nodig hebben. Deze methode heeft echter wel als + nadeel dat de doorvoersnelheid beperkt is. + Nog een probleem met seriele interfacing is dat de + ontvanger dit signaal weer netjes in mekaar kan zetten tot + de oorspronkelijke data. Hiervoor moeten we een methode + verzinnen die redelijk snel kan zijn, zonder al te veel + moeilijkheden. De RS232C communicatie die we gebruiken + heeft een redelijk simpele methode om de data te + versturen. Er wordt aangenomen dat de ontvanger weet op + welke snelheid er verzonden wordt, en stelt de + ontvangstklok in op die snelheid. De zender wil op een + gegeven moment iets overzenden. Om de ontvanger opmerkzaam + hierop te maken (triggeren) wordt het signaal wat normaal + gesproken in rusttoestang hoog is, laag gemaakt. Dit wordt + gedaan voor 1 gehele periode van de zend frequentie. + Hierna wordt op dezelfde snelheid de data overgestuurd, + ook weer geinverteerd. Afhankelijk van het protocol kan + hier achter die data nog een parity bit komen. Hierachter + worden nog 1 of 2 stopbits geplaatst. Meestal wordt er + voor 1 stopbit gekozen voor een iets hogere doorvoer. + Deze methode van zenden is A-SYNCHROON. + Via RCD wordt op dezelde methode data ontvangen. + + + C O N T R O L / S T A T U S + + Ik bespreek alleen de meest toegepaste signalen, enkelen + die niet gebruik worden op de MSX, en ik dus helaas ook + niet ken, bespreek ik niet. + + RTS is ervoor om te zorgen dat je aan de zender door kunt + geven dat je op dat moment geen data meer kunt/wilt + ontvangen. De zender hoort hier dan rekening mee te + houden. + Door RFS af te scannen tijdens het zenden, weet de zender + dat deze op een gegeven moment op moet houden, als de + ontvanger dit wil. + Deze RTS/RFS worden in sommige oude communicatie + programma's niet gebruikt, dan wordt er Xon/Xoff handshake + gebruikt, wat inhoud dat de zender reageert op bepaalde + karaktercodes door te starten of stoppen met zenden. + Met DSR geeft een device aan dat ie actief is, dus dat er + data naartoe verzonden mag worden. + DTR is het signaal wat je afgeeft, om aan te duiden dat je + actief bent, verwar dit niet met RTS, want RTS werkt + alleen als DTR geldig is. + Met DCD heeft de tegenpartij aan dat ie herkent heeft dat + er data komt, een modem kan hier bv. mee aangeven dat er + een verbinding is met een ander modem. + CIN is een signaal wat de tegenpartij, met deze toepassing + meestal een modem, aan dat er een oproep is. + TSET en RSET zijn klokfrequenties voor ontvangen/zenden + van data. + Het complete backward channel werkt zoals de equivalente + functies hierboven. + + + D E P R A K T I J K + + In de praktijk zijn meestal niet alle functies opgenomen in + de interface. Zo heb ik nog nooit een MSX RS232C interface + gezien met de TEST functies. Een MSX RS232C interface met + een werkende backward channel is ook ver te zoeken, maar de + Philips NMS121x is er wel op voorbereid. Dit vereist een + andere kabel, met een andere aansluiting IN de interface. + Heeft wel als nadeel dat je dan maar 1 aansluiting kunt + gebruiken, daar channel B dan ook op de aansluiting van + channel A komt. Wat ik ook nog niet gezien heb op de MSX + RS232C interfaces is de rate/frequency selector. + + Even een korte opsomming over "tekortkomingen" op twee MSX + RS232C interfaces. Deze tekortkomingen zijn in feite niet + echt nodig, en worden op andere systemen ook niet gebruikt, + bij mijn weten. + + + De NMS121x interfaces : + + Niet ondersteund : DRS, STF, RIL, LL, TI + Op voorbereid : complete backward channel + + + De SONY HBI1 RS232C interface (MSX standaard) : + + Niet ondersteund : DRS, STF, RIL, LL, TI, TSET in, TSET out, + RSET, complete backward channel + + Deze functies zullen ook niet op andere standaard MSX-RS232C + interfaces opgenomen zijn, simpelweg omdat deze functies + niet gedefinieerd zijn door ASCII. + + Erik Maas diff --git a/sunrise_special/7/Luna.md b/sunrise_special/7/Luna.md new file mode 100644 index 0000000..8c6f786 --- /dev/null +++ b/sunrise_special/7/Luna.md @@ -0,0 +1,197 @@ + Noot vooraf: dit programma had op Sunrise Special #6 moeten + staan, maar stond er dus niet op. Vergissen is menselijk en + dus ook Kasperlijk zullen we maar denken. Hier nogmaals de + tekst, en als er geen hele rare dingen gebeuren staat LUNA + nu wel op de disk... + + + L U N A + + + B E T E R E D I S K - C A C H E + + Op Sunrise Magazine #11 werd DOS2CASH besproken. Nu is er + alweer een veel beter programma om te cachen! Het heet Luna + - en heeft volgens mij niet veel met een lunapark te maken - + en is dit jaar nog gemaakt. Het is dus een vrij nieuw + programma. + + Het is net als DOS2CASH afkomstig uit Japan, en het komt van + een reeks diskettes met allerlei PD programma's uit Japanse + BBS'en. + + + H A R D D I S K ! + + Luna kan ook de harddisk cachen, en het helpt ook nog! Luna + vertraagt wel een beetje bij de eerste keer laden, maar als + je iets uit het cache-geheugen laadt, gaat het echt + razendsnel. + + Voor turbo R gebruikers is er het goede nieuws dat het + programma ook een soort R800-drive bevat. Je kunt nu per + drive instellen of er gelezen en geschreven moet worden met + de R800 mode aan. + + + G E H E U G E N N E M E N + + Met de volgende functies kun je aangeven hoeveel geheugen + LUNA.COM moet innemen. + + nnnn : Gewoon een getal van 80 tot 4096. Dit is de ruimte, + in kB's, die Luna gebruikt als cache-geheugen. + + Snnn : Hier geeft het getal niet het aantal kB dat Luna + gebruikt, maar het aantal mapper segmenten. Elk + segment is 16 kB groot. + + Ennnn: Met E wordt de vrije ruimte aangeduid. + + ESnnn: Hier is het getal natuurlijk het aantal vrije mapper + segmenten. + + De minimale hoeveelheid geheugen die Luna nodig heeft is + overigens 80 kB, oftewel 5 segmenten. + + + C H E C K T I M E + + Met de letter T kun je een bepaalde tijd opgeven. Deze tijd + staat voor een aantal interrupts. Als je er nu binnen deze + tijd al een disk-aanroep is geweest, controleert Luna niet + of dezelfde disk nog in de drive zit. Als je computer op 50 + Hz staat is 50 eenheden uiteraard 1 seconde. + + Bijv. LUNA T300 om bij een computer op 60 Hz pas na (300/60 + =) 5 seconde weer te checken op de bootsector, en bij 50 Hz + (300/50 =) 6 seconde te wachten. + + + F L A S H E N + + Bij de optie F heeft de help-optie (/H of /?) van Luna het + over flash time. Wat dit precies inhoudt is me nog + onduidelijk. Ik vermoed dat het gewoon het laten knipperen + van een aantal LED's bij het weer opnieuw herkennen van een + disk. In ieder geval geef je met Fnnnnn de tijdsduur van het + knipperen aan. + + + L E D S S P E C I F I C E R E N + + Bij de opties die hieronder vermeld staan kun je de volgende + letters gebruiken: + + C: CAPS + K: KANA; dit is alleen bij Japanse computers van toepassing + P: PAUSE: alleen bij MSX turbo R + T: turbo: idem + + Deze staan voor de bijbehorende LED's, en als de handeling + verricht wordt, worden de LED's aangemaakt als ze aanstaan, + en uitgemaakt als ze uitstaan. Gewoon ge�nverteerd dus. + + Met LC kun je de LED's specificeren die ge�nverteerd worden + bij het cachen. Dus bij alle lees- en schrijfopdrachten + waarbij het cache-geheugen gebruikt wordt. + + LF geeft aan welke LED's worden gebruikt bij het flashen. LA + doet hetzelfde, maar dan bij een zogenaamde all-flash. Ik + vraag me echter af wat al dit geflash inhoudt. Als iemand + meer weet: let me know! + + + P R O T E C T E D S E C T O R S + + Om een of andere reden is het mogelijk sectors te + beschermen. Waartegen is me onduidelijk, maar het is + mogelijk. Met de optie /F kun je dit uitschakelen. + + Achter F kun je gewoon de eerste normale sector opgeven, en + dan geldt dat voor alle drives. Het is echter ook mogelijk + om drives te zetten achter F. Dan geldt de sector alleen bij + die bepaalde drives. Uiteraard kun je dus ook meerdere keren + F gebruiken. + + Bijv. LUNA FABC29 als de protected sectors van drives A: t/m + C: van 0 tot en met 28 lopen. + + + P E R D R I V E U I T + + Met A kun je aangeven welke drives geen automatische flash + hebben. Het doel hiervan is - je raadt het al - me + onduidelijk. De drives komen gewoon achter de A. + + D is om bij bepaalde drives het cachen uit te zetten. Bij de + HG SCSI interface zou de cache wel eens alleen maar + vertragend kunnen werken, en dan is deze optie natuurlijk + wel handig. (Luna blijft echter handig, want je moet toch af + en toe met gewone disks werken.) + + Bijv. LUNA dACD om drive A:, C: en D: niet te cachen. (Voor + de duidelijkheid gebruik ik een kleine D + + + R 8 0 0 - D R I V E + + Met de optie R en W kun je aangeven of de R800 moet worden + aangezet bij respectievelijk het lezen (Read) en schrijven + (Write). + + Als je een turbo R hebt, kun je het beste al je drives met + de R800 aan laten lezen. Schrijven gaat soms fout bij gewone + drives, maar harddisk en RAMdisk kunnen het zonder problemen + aan. + + Bijv. LUNA rABCDEFH wABCDH om, zoals in mijn geval, alleen + drive E: en F: niet met R800 aan beschreven te laten worden. + + + O P T I E S + + /U : Upper RAM mode aan. De bedoeling hiervan is me niet + compleet duidelijk. Ik vermoed echter dat Luna in dit + geval liever de hogere mapper-segmenten gebruikt. + + /P : Stored PCM aan. Het klinkt wel spectaculair, maar is me + helemaal niet duidelijk. + + /S : Seek speed up uit. Ook dit kan ik niet verklaren. In + ieder geval zal het wel trager worden als je deze optie + gebruikt. + + /F : FAT protect off. Met deze optie kun je het beschermen + van de FAT tegengaan. Zie ook de uitleg bij F. + + /D : Auto flash off. Tja... + + /M : Message off. Zo krijg je geen overzicht van de + instellingen. Met redirection naar NUL krijg je + overigens helemaal niks op het scherm. Dus met LUNA + >NUL. + + /C : De opties die nu achter LUNA staan, worden in LUNA.COM + bewaard. Als LUNA.COM gePOPCOMd is, wordt dit weer + ongedaan gemaakt door het saven zelf. Hierna moet je + dus even opnieuw POPCOMmen. + + /J : Laat de bewaarde parameters op het scherm zien. Handig + wanneer je maar ��n ding wilt aanpassen. Want bij /C + worden de oude paramters ongedaan gemaakt. + + /R : Haal Luna uit het geheugen. + + /H of /? : Geeft een beknopt overzicht van alle opties van + Luna + + + L U N A E N M A P + + Helaas pindakaas. Als je Luna in het geheugen hebt, en je + runt MAP, dan blijft de computer hangen bij de volgende + disk-access. Als je MAP dus toch nodig hebt, moet je eerst + even Luna verwijderen met LUNA /R. + + Kasper Souren diff --git a/sunrise_special/7/ML Technieken.md b/sunrise_special/7/ML Technieken.md new file mode 100644 index 0000000..9bf65c2 --- /dev/null +++ b/sunrise_special/7/ML Technieken.md @@ -0,0 +1,481 @@ + M L T E C H I E K E N ( 1 ) + + + Het lijkt mij een goed idee om naast de cursus BASIC + technieken op Sunrise Magazine een cursus ML technieken te + starten op de Special. Ook dit is geen programmeercursus + maar een verzameling tips en truuks en manieren hoe je iets + het beste kunt aanpakken. Ik ben overigens niet van plan om + deze cursus alleen te schrijven, maar zal zeker een aantal + ML programmeurs met meer ervaring vragen hun geheimen prijs + te geven in deze rubriek. Deze keer een paar simpele + problemen waar beginners tegenaan zullen lopen. + + Ik zal bij vergelijking van routines tellingen van klokcycli + en bytes geven, bij de klokcycli ga ik uit van een Z80. Over + het algemeen zal een routine die sneller is op de Z80 ook + sneller zijn op de R800, maar dit is geen wet van Meden en + Perzen. + + + B Y T E U I T T A B E L H A L E N + + Stel je hebt een tabel en je hebt een waarde in A die + aangeeft de hoeveelste byte van de tabel je wilt hebben. + Deze byte moet uiteindelijk in A terechtkomen. Hiervoor moet + je het adres in de tabel uitrekenen, het liefst zou je dat + doen met + + LD HL,Tabel + ADD HL,A + LD A,(HL) + + maar de instructie ADD HL,A bestaat natuurlijk niet, want je + kunt geen 8 bits register bij een 16 bits register optellen. + We zullen de instructie ADD HL,A dus zelf moeten maken. Er + zijn op z'n minst twee oplossingen mogelijk. De eerste is + degene die ik meestal gebruik: + + klokcycli bytes + + LD E,A 5 1 + LD D,0 8 2 + LD HL,Tabel 11 3 + ADD HL,DE 12 1 + LD A,(HL) 8 1 + ---- --- + 44 8 + + De eerste twee instructies betekenen LD DE,A. Vervolgens + wordt DE bij HL opgeteld en de byte uit de tabel gelezen. + Het nadeel hiervan is dat je het DE register (of eventueel + het BC register) gebruikt. De volgende oplossing doet dat + niet: + + klokcycli bytes + + LD HL,Tabel 11 3 + ADD A,L 5 1 + LD L,A 5 1 + LD A,0 8 2 + ADC A,H 5 1 + LD H,A 5 1 + LD A,(HL) 8 1 + ---- --- + 47 10 + + + ADD A,L; LD L,A is een substituut voor ADD L,A (dat niet + bestaat). Vervolgens moet nog de carry bij H worden opgeteld + (LD A,0; ADC A,H; LD H,A). Het voordeel is dat het DE (of + BC) register niet wordt gebruikt, maar deze routine is iets + trager (3 klokcylci is 0.84 microseconde, niet echt een + verschil dat je snel zult merken) en wat erger is: 2 bytes + langer. Ik heb vaak problemen dat mijn code te groot wordt, + en ik heb daarom een grote voorkeur voor kortere + oplossingen, zelfs als dat een paar klokcycli trager is. + + Er is nog een alternatief dat sterk op de vorige lijkt, hier + wordt alleen een andere manier gekozen om de carry bij H op + te tellen: + + klokcycli bytes + + LD HL,Tabel 11 3 + ADD A,L 5 1 + LD L,A 5 1 + JR NC,Label 13/8 2 + INC H 0 /5 1 + Label: LD A,(HL) 8 1 + ---- --- + 42 9 + + Het grappige van deze routine is dat hij ondanks de + voorwaardelijke sprong altijd even snel is, dit komt omdat + als hij springt (13 klokcycli) hij de INC H niet doet, en + als hij niet springt (8 klokcycli) hij de INC H (5 + klokcycli) er nog bij doet, waardoor de LD A,0; ADD A,H; LD + H,A constructie van de vorige oplossing (18 klokcycli, 4 + bytes) dus wordt vervangen door 13 klokcycli en 3 bytes. + Vandaar de 5 klokcycli en 1 byte winst. + + Deze oplossing is dus sneller dan de oplossing met DE (44 + klokcycli), maar het kost weer een byte meer (9 in plaats + van 8). Als je ruim in je geheugen zit en die ene byte extra + je geen bal kan schelen is deze oplossing dus het beste + (lees: snelste), en als je het DE register al voor iets + anders in gebruik hebt is het zeker de beste. Maar als elke + byte telt geef ik de voorkeur aan de eerste oplossing. Nog + een nadeel van deze oplossing is dat het een extra label + geeft en of dat een nadeel is is vooral afhankelijk van de + assembler die je gebruikt. + + Tot slot nog even hoe het niet moet: + + klokcycli bytes + + LD IX,Tabel 15 4 + LD (Poke+2),A 14 3 + Poke: LD A,(IX+0) 20 3 + ---- --- + 49 10 + + Dit is verreweg de meest lelijke oplossing die ik kan + bedenken. Hij is ook nog eens de traagste en net zo lang als + de langste oplossing tot nu toe. Bovendien doe je iets dat + eigenlijk helemaal niet mag (het kan niet eens als je + programma op ROM wordt gezet!), namelijk het poken in je + code. Indexregisters zijn traag maar erg handig bij tabellen + met een variabel beginadres waaruit je bytes op vaste + plaatsen wilt lezen. (Er zijn namelijk geen LD A,(IX+B) + instructies of zoiets, het is altijd LD A,(IX+n), waarbij n + een constante tussen -128 en +127 is.) Ik heb daar al eens + een tekst over geschreven op de Special. Hier is het precies + andersom: een vast beginadres en een variabele plaats. Dat + doe je dus NIET met indexregisters. Het ziet er in je source + erg kort uit (3 regels, terwijl de andere oplossingen + respectievelijk 5, 6 en 7 regels in beslag nemen), maar + instructies met IX en IY zijn gewoon erg traag. + + Er is nog ��n truuk die je kunt gebruiken als je echt + maximale snelheid nodig hebt: zorg dat je tabel op een adres + begint waarvan de lowbyte gelijk is aan 0! Dus bijvoorbeeld: + + Tabel: EQU #D000 + + klokcycli: bytes: + + LD H,#D0 8 2 + LD L,A 5 1 + LD A,(HL) 8 1 + --- --- + 21 4 + + Deze routine is twee keer zo snel en twee keer zo kort als + de snelste en kortste routines die we tot nu toe + tegenkwamen, maar dat komt door de speciale eis die aan de + tabel wordt gesteld. Op zich heel mooi maar vaak onhandig om + toe te passen, zeker als je veel tabellen hebt. Toch is dit + zeker iets wat je in gedachten moet houden voor als je eens + in snelheidsnood zit. + + + J U M P T A B E L + + Iets wat veel met het vorige onderwerp te maken heeft is een + jumptabel. Vergelijk dit maar met ON A GOTO in BASIC. Altijd + een zeer snelle methode om een keuze uit een redelijk groot + aantal alternatieven te maken. Bij slechts een paar + alternatieven is CP x; JP Z,y korter en sneller. + + Ik heb hiervoor altijd een standaardroutine met de naam + Jump. In A staat het nummer van de gewenste sprong en in HL + het begin van de jumptabel. Die routine is als volgt: + + klokcycli: bytes: + + Jump: DEC A 5 1 + ADD A,A 5 1 + LD E,A 5 1 + LD D,0 8 2 + ADD HL,DE 12 1 + LD E,(HL) 8 1 + INC HL 7 1 + LD D,(HL) 8 1 + EX DE,HL 5 1 + JP (HL) 5 1 + ---- --- + 68 11 + + De DEC A is nodig omdat het eerste adres in de tabel + natuurlijk offset 0 heeft. Daarna verdubbelen we A omdat een + adres 2 bytes lang is. Daarna tellen we A bij HL op via DE, + omdat we net hebben gezien dat dat de korste oplossing is en + we DE sowieso nodig hebben. Een instructie LD DE,(HL) + bestaat helaas niet dus doen we dat met LD E,(HL); INC HL; + LD D,(HL). Tenslotte verwisselen we DE en HL (want het adres + waarnaar we moeten springen staat in DE en moet in HL + terecht komen) en springen we naar dat adres toe. Volgens + mij is er geen betere oplossing hiervoor, de eis dat L + gelijk moet zijn aan 0 (zodat we alleen maar LD L,A hoeven + te doen in plaats van LD E,A; LD D,0; ADD HL,DE) is hier + zeer onhandig. + + - Deze tekst wordt vervolgd in de volgende submenu-optie - + + + + - Dit is het tweede gedeelte - + + M L T E C H N I E K E N ( 1 ) + + + C O M P A R E + + Veel beginnende programmeurs hebben moeite met de instructie + CP, wat een afkorting is voor ComPare. Eigenlijk is het + helemaal niet moeilijk als je maar weet hoe het werkt. + + De volgende CP instructies zijn mogelijk: + + klokcycli: bytes: + + CP (HL) 8 1 + CP (IX+n) 20 3 + CP (IY+n) 20 3 + CP A 5 1 + CP B 5 1 + CP C 5 1 + CP D 5 1 + CP E 5 1 + CP H 5 1 + CP L 5 1 + CP n 8 2 + + Bij een CP x instructie zal de Z80 de vlaggen zo zetten als + ook bij een SUB x instructie gebeurt, zonder de waarde van A + te veranderen. Er zijn dus drie gevallen mogelijk: + + - als x kleiner is dan A dan komt er geen carry want je kunt + x gewoon van A aftrekken zonder dat je een negatieve + uitkomst krijgt + - als x gelijk is aan A dan komt er een zero want A-x is dan + gelijk aan 0, er is GEEN carry want er is nog net geen + negatieve uitkomst + - als x groter is dan A dan komt er een carry want er is een + nieuwe uitkomst + + Samengevat: + + A >= x NC + A < x C + A = x Z + A <> x NZ + + Je hoeft dit niet uit je hoofd te kennen, je kunt gewoon + beredeneren wat er met de zero- en carryflag gebeurt als je + x van A af zou trekken. + + Als je zoals ik in het vorige onderdeel al opmerkte + slechts weinig alternatieven hebt, dan is het sneller om de + volgende constructie toe te passen: + + klokcycli: bytes: + + CP 1 8 2 + JR Z,Keuze1 8/13 2 + CP 2 8 2 + JR Z,Keuze2 8/13 2 + Keuze3: ..... + + Dit neemt 8 bytes in beslag (de jumproutine 11) en het neemt + 8 + 13 = 21 klokcycli als A=1 en 8 + 8 + 8 + 13 = 37 + klokcycli in beslag als A=2 en 8 + 8 + 8 + 8 = 32 klokcycli + als A=3. Zo heb je dus bij drie alternatieven minder bytes + en minder klokcycli nodig in vergelijking met de routine + Jump. (Indien JP nodig is in plaats van JR neemt het aantal + bytes met 2 toe waardoor het op 10 komt (nog steeds kleiner + dan 11) en het aantal klokcycli is respectievelijk 18 voor + A=1 en 36 voor A=2 en A=3. Nog steeds veel sneller dan de 68 + klokcycli van Jump.) We gaan er hier overigens wel vanuit + dat A alleen de waardes 1, 2 en 3 kan aannemen, want bij + deze routine zal ook bij A=0 en A=4 t/m A=255 de routine + Keuze3 worden uitgevoerd. + + + L U S S E N + + De Z80 heeft een simpele voorziening voor lussen in de vorm + van DJNZ (Decrease, Jump if NonZero). Hierbij is de + lusteller altijd B en is de maximale luslengte dus 256. Een + luslengte van 256 kan daarbij bereikt worden met 0 als + startwaarde van B!!! Een voorbeeld: + + klokcycli: bytes: + + LD B,10 8 2 + Lus: DJNZ Lus 14/9 2 + --- + 4 + + In totaal vergt deze lus 8 + 9*14 + 9 = 143 klokcycli. Deze + lus doet niets boeiend, alleen even wachten, 40.04 + microseconde om precies te zijn. Je kunt het ook zo + programmeren: + + klokcycli: bytes: + + LD D,10 8 2 + Lus: DEC D 5 1 + JR NZ,Lus 13/8 2 + --- + 5 + + Ik heb het expres met D gedaan om te laten zien dat je nu + niet meer aan B bent gebonden als lusvariabele. Het kost ��n + byte meer en verder vergt deze lus 8 + 10*5 + 9*13 + 8 = 183 + klokcycli (51.24 microseconde). Met DJNZ bespaar je dus + zowel ruimte als tijd, maar alleen B kan gebruikt worden als + lusvariabele. + + Grotere lussen kunnen gemaakt worden door geneste DJNZ- + lussen, bijvoorbeeld: + + LD B,100 + BuitensteLus: PUSH BC + LD B,100 + BinnensteLus: ...... + ...... + DJNZ BinnensteLus + POP BC + DJNZ BuitensteLus + + Hierbij wordt de binnenste lus 100 * 100 = 10000 maal + uitgevoerd. Dit is alleen geschikt voor vaste luslengte, en + dan vooral als er ook echt sprake is van een binnenste en + een buitenste lus. Bijvoorbeeld de binnenste lus doet iets + met alle dingen van ��n regel en de buitenste lus loopt alle + regels langs. Bij een variabele luslengte of als het + eigenlijk gewoon de bedoeling is dat de binnenste lus 10000 + maal wordt herhaald, is de volgende oplossing het meest + geschikt: + + LD BC,10000 + Lus: ...... + ...... + DEC BC + LD A,B + OR C + JR NZ,Lus + + Bij een 8 bits DEC (DEC A, B, C, etc.) wordt de Zeroflag + gezet als 0 wordt bereikt. Bij een 16 bits DEC is dit niet + het geval, DEC BC zet de Z-flag dus NIET als BC gelijk wordt + aan 0. Daarom kijken we met LD A,B; OR C of zowel B als C + gelijk zijn aan 0, want dan is automatisch BC gelijk aan 0. + + Dit doet me trouwens denken aan een verschil tussen DEC A en + SUB 1. Op het eerste gezicht doen deze twee instructies + exact hetzelfde, namelijk het verlagen van A met 1. Het + verschil zit hem echter in de vlaggen: bij DEC wordt de + carryflag niet be�nvloed, bij SUB 1 wel! Dus als A gelijk is + aan 0 en je doet DEC A, dan wordt er geen carry gezet, en + als A gelijk is aan 0 en je doet SUB 1, dan wordt de carry + wel gezet. Dit is echt zo'n irritant verschil waar je op + moet letten, want het kan soms hele vage bugs veroorzaken + omdat je ervan uitgaat dat de carryflag gezet wordt en het + gebeurt niet. [Ik had ergens SUB 1 in een source staan, en + toen zei iemand aan wie ik die source liet zien dat ik daar + DEC A van moest maken, omdat dat hetzelfde zou doen en + sneller is en minder bytes in beslag neemt. Ik had dat toen + veranderd en merkte pas later, toen diegene alweer weg was, + dat het programma niet meer werkte!] + + + 1 6 B I T S L D + + Veel 16 bits instructies die je vaak nodig hebt zoals LD + DE,HL; LD IX,HL en LD DE,IY bestaan niet. Hiervoor zullen we + dus andere oplossingen moeten zoeken. + + Ten eerste deze groep: + + LD BC,DE + LD BC,HL + LD DE,BC + LD DE,HL + LD HL,DE + LD HL,BC + + Deze instructies bestaan helaas niet maar ze zijn heel + makkelijk te maken met 8 bits LD instructies: + + LD BC,DE wordt: LD B,D + LD C,E + LD DE,HL wordt: LD D,H + LD E,L + etc. + + Zo'n "16 bits LD" kost 2 bytes en 10 klokcycli. Sommige + programmeurs gebruiken de volgende methode: + + LD BC,DE wordt: PUSH DE + POP BC + LD DE,HL wordt: PUSH HL + POP DE + + Dit kost ook 2 bytes maar is veel trager, want een PUSH kost + 12 klokcycli en een POP 11, waardoor het totaal op 23 komt. + Ofwel meer dan twee keer zo lang. + + Voor de tweede groep is dit (als je je aan de offici�le + instructieset van de Z80 houdt) niet mogelijk: + + LD IX,HL + LD IX,DE + LD IX,BC + LD IX,IY + LD HL,IX + LD DE,IX + LD BC,IX + LD IY,IX + + en dezelfde instructies met IY kun je alleen maken met een + PUSH en een POP. Bijvoorbeeld: + + klokc: bytes: + + LD IX,HL wordt: PUSH HL 12 1 + POP IX 15 2 + ---- --- + 27 3 + + LD BC,IY wordt: PUSH IY 16 2 + POP BC 11 1 + ---- --- + 27 3 + + Op de R800 [of met illegale instructies van de Z80 die je + dus niet mag gebruiken omdat ze bij de Z80's niet getest + zijn en dus fout kunnen gaan] kan het wel met 8 bits LD + instructies. Dit kan echter alleen met DE en BC, niet met + HL! Ook LD IX,IY en LD IY,IX kunnen alleen met PUSH en POP + worden opgelost. We schakelen nu bij het tellen van + klokcycli nu even over op klokcycli van de R800. Ik laat + voor LD IX,DE en LD BC,IY van beide alternatieven de + tellingen zien: + + LD IX,DE wordt: PUSH DE 4 1 + POP IX 4 2 + --- --- + 8 3 + + of: LD IXH,D 2 2 + LD IXL,E 2 2 + --- --- + 4 4 + + LD BC,IY wordt: PUSH IY 5 2 + POP BC 3 1 + --- --- + 8 3 + + of: LD B,IYH 2 2 + LD C,IYL 2 2 + --- --- + 4 4 + + Op de R800 is de variant met 8 bits LD dus twee keer zo snel + maar neemt wel een byte meer in beslag. Bovendien moet je + wel goed nadenken omdat niet alles mogelijk is. Maar als je + daar een fout mee maakt zal de compiler je wel waarschuwen. + Nog een nadeel hiervan is dat GEN80 en WB-ASS2 geen IXL, + IXH, IYL en IYH ondersteunen en je dus met DB's moet gaan + werken (DB #DD voor IX en DB #FD voor IY gevolgd door de + instructie op H of L). + + Dit was het voor deze keer. Veel succes met het programmeren + in ML, met vragen kun je natuurlijk altijd bij de redactie + terecht. + + Stefan Boer diff --git a/sunrise_special/7/Midi Cursus.md b/sunrise_special/7/Midi Cursus.md new file mode 100644 index 0000000..6018fae --- /dev/null +++ b/sunrise_special/7/Midi Cursus.md @@ -0,0 +1,563 @@ + M I D I C U R S U S + + + C O N T R O L C H A N G E S + + Na de vorige keer een verhaal te hebben afgestoken over de + opbouw van MIDI-commando's wil ik het deze keer eens hebben + over de werkwoorden in de MIDI-taal: de CONTROL CHANGES. + + Zoals de vorige keer al opgemerkt (en ongetwijfeld nog + bekend...) begint een Control Change hexadecimaal met een B. + Daarachter komt, om het byte volledig te maken, een + hexadecimaal getal tussen 0 en F om het MIDI-kanaal aan te + wijzen, waarbij (zoals bekend) 0 kanaal 1 is en F kanaal 16. + Na dit statusbyte (want het begint met een getal groter of + gelijk aan 8) volgen twee databytes. Het eerste databyte + geeft de te veranderen controller aan, de tweede de waarde + die de controller krijgt. + + Ok�, tot dusver de herhaling; zijn er nog vragen? + + "Ja, wat is een controller?" + + Euh ja, goede vraag, maar niet zo goed te beantwoorden. Ik + kan simpelweg een cirkelredenering toepassen en zeggen dat + een controller datgene is, dat met behulp van Control Change + is te veranderen, maar dat is taalkundig niet erg netjes + (maar wel makkelijk, nietwaar heren politici?). + + Laat ik als antwoord op die vraag teruggrijpen op het + ontstaan van MIDI: + + Door de indeling van MIDI in status- en databytes + (respectievelijk die bytes groter dan of gelijk aan 128 en + kleiner dan 128) en de indeling van de statusbytes in vier + bits voor status en vier bits voor MIDI-kanaal bleef er voor + MIDI niet bijster veel meer over om te regelen. De vier bits + die de status aangeven (en dus ook nog MOETEN beginnen met + een 1, daar anders het getal kleiner is dan 128) kunnen + slechts 8 verschillende statussen aanduiden. Niet echt veel + om alle nuanceverschillen in muziek mee aan te sturen... + Daarom ontstond er de Control Change, als een soort + werkwoord voor de MIDI-taal: Alle parameters, die te + veranderen zijn met behulp van MIDI in een + keyboard/synthesizer en geen eigen Status hebben, worden + aangestuurd met de Control Change. In totaal zijn dus met + behulp van Control Change 128 verschillende parameters + (oftewel controllers) aan te sturen (databytes 00 t/m 7F). + Tot zover nog volledig duidelijk, hoop ik, en dus volgen nu + de uitzonderingen: + + De controllers (waarvan u dus nog steeds niet weet wat het + zijn; geduld, het wordt u wel duidelijk. Blijf rustig + doorlezen) zijn onderverdeeld in Continue controllers, + Switch controllers, geregistreerde en niet-geregistreerde + controllers. + + De Continue controllers zijn wederom onderverdeeld in + 14-bits controllers (dus twee databytes, later meer) en + 7-bits (oftewel 1 data-byte) controllers. + + De indeling in databytes is alsvolgt: + + 00h t/m 1Fh: 14-bits Continue controllers (MSB) + 20h t/m 3Fh: 14-bits Continue controllers (LSB) + 40h t/m 45h: Switch-controllers + 46h t/m 5Fh: 7-bits Continue controllers + 60h t/m 61h: data plus en data min (zie verder) + 62h t/m 65h: geregistreerde/niet-geregistreerde controllers + 66h tot 77h: nog niet gedefinieerd + 78h t/m 7Fh: Modusboodschappen (zie verder) + + + 14-BITS CONTINUE CONTROLLERS (MSB EN LSB) + + Als het eerste databyte na de statusbyte een getal is tussen + 00h en 3Fh, betreft het die controllers, die een waarde + kunnen bevatten tussen 0 en 16384. De databytes tussen 00h + en 1Fh geven de grove afstemming; die tussen 20h en 3Fh de + fijnafstemming. Controller 01h en 21h zijn dus DEZELFDE + controller, waarbij 01h de grove afstemming regelt en 21h de + fijnafstemming! V��r het ontstaan van de GM en GS-standaard + waren slechts 13 van de 32 14-bits Continue controllers + gedefinieerd: + + + 0 1 H / 2 1 H : M O D U L A T I O N + + Het doel van de modulation is om een geluid expressiever + weer te geven. Hoe dat gebeurt is aan de fabrikant om te + beslissen! De meest gebruikte modulations zijn de vibratie + (voor diegenen, die niet weten wat dat is: trilling...) en + de tremolo (variatie in de amplitude van een geluid). + + + 0 2 H / 2 2 H : B R E A T H C O N T R O L + + Omdat de DX7-synthesizer van Yamaha het eerste instrument + wat met een standaard in MIDI, zijn veel van zijn + controllers overgenomen. E�n van deze controllers was de + Breath Control. Voor diegene, die nog nooit iemand bezig + heeft gezien met de Breath Controller (en ik denk dat dat de + meesten zijn, daar deze controller eigenlijk alleen door + Yamaha ondersteund wordt en dan nog maar in beperkte mate. + Dadelijk wordt wel duidelijk waarom...): De Breath + Controller is een plastic mondstuk, waarin je blaast. + Naarmate je harder blaast, wordt de Breath Control hoger. + Het grote nadeel van deze controller is de mate van blazen + die nodig is om de maximale uitslag te krijgen: + Keyboard-spelers die rood aanlopen waren echt geen + zeldzaamheid, vooral niet als men roker was en/of net een + weinig (of wat meer) bier achterover had geslagen... + + + 0 4 H / 2 4 H : F O O T C O N T R O L L E R + + Speciaal voor rokers en drankorgels (en al de anderen, die + niet voor gek wilden staan met een buis in hun mond) + ontstond de Foot controller. Deze doet exact hetzelfde als + de Breath controller, maar wordt (hoera!) met de voet + bediend. + + + 0 5 H / 2 5 H : P O R T A M E N T O T I M E + + Deze controller regelt de snelheid van het portamento. + + "Euh, pardon? Wat is een portamento?" + + Jij weer? Nou vooruit: Portamento is een geleidelijke + overgang tussen twee noten. Denk bijvoorbeeld aan een + violist, die zijn vinger over een snaar laat glijden of aan + Brian May op overdrive-gitaar. Hoe hoger de waarde hoe + sneller naar de volgende noot wordt 'toegelopen'. + + (P.S. Er is ook nog een Portamento Switch-controller: Pas + als deze aan staat, werkt het portamento...) + + + 0 6 H / 2 6 H : D A T A E N T R Y + + Er zijn ook controllers, die geen ruimte meer hebben voor + databytes, doordat ze voor het aanduiden van de controller + al beide databytes nodig hebben. Een voorbeeld hiervan is de + verderop behandelde geregistreerde en ongeregistreerde + controllers. Om dergelijke controllers toch te kunnen + veranderen bestaat er de Data entry. De waarde die met deze + controller wordt gegeven wordt gebruikt om de LAATST gekozen + controller (geregistreerd of ongeregistreerd) te veranderen. + Heeft u nog geen controller gekozen gehad, heeft deze Data + entry ook geen effect... + + + 0 7 H / 2 7 H : M A I N V O L U M E + + Met behulp van deze controller wordt het volume van ��n + MIDI-kanaal veranderd. Deze controller is verreweg de meest + gebruikte, daar dit de enige standaard-methode is om het + volume van een keyboard/synthesizer te veranderen. + + + 0 8 H / 2 8 H : B A L A N C E + + Verwar deze controller niet met controller 10h/30h! De + balance regelt NIET de van audio-systemen bekende balance. + Daarvoor dient controller 10h/30h! De Balance regelt de + verhouding tussen twee geluiden, wanneer een voice is + samengesteld uit twee geluiden. Deze controller wordt + vrijwel alleen gebruikt bij synthesizers en dan nog niet + vaak! + + + 0 A H / 2 A H : P A N + + Deze controller be�nvloedt het stereobeeld van ��n + MIDI-kanaal. Wanneer de waarde 0 wordt meegestuurd bevindt + het geluid zich uiterst links. Naarmate de waarde hoger + wordt, verplaatst het geluid zich naar rechts, totdat de + maximale waarde is gegeven en het geluid zich dus uiterst + rechts bevindt. + + + 0 B H / 2 B H : E X P R E S S I O N + + Deze controller bepaalt het volumebeeld ter verfijning van + controller 07h/27h (Main volume). Voor die oplettende + mensen, die dus nu vragen of het volume dus in totaal + 28-bits geregeld wordt (controller 07h/27h=14-bits + + controller 0Bh/2Bh=14-bits) moet ik antwoorden: Officieel + wel, maar verreweg de meeste instrumenten (sterker nog: ik + ben nog nooit anders tegengekomen) herkennen alleen de MSB + van alle controllers. En om dan toch het volume wel met + behulp van 14-bits te regelen is de Expression ontstaan. + + + 10h/30h T/M 13h/33h: GENERAL PURPOSE + + Deze controllers zijn speciaal in het leven geroepen om de + diverse fabrikanten een mogelijkheid te geven om toch van + elkaar af te wijken. Deze controllers zijn dus NIET + standaard; elke fabrikant heeft ze met eigen controllers + ingevuld. Om weer terug te grijpen naar de vergelijking met + taal: Dit is het dialect van MIDI. + + + S W I T C H - C O N T R O L L E R S + + Dit zijn er in totaal 5. Deze controllers kennen slechts + twee standen: Aan en uit. Maar omdat MIDI alleen met 7-bits + databytes kan werken is 00h t/m 3Fh 'uit' en 40h t/m 7Fh + 'aan'. Persoonlijk vind ik dat ze deze switches best op + bit-niveau hadden kunnen zetten; dus 1 controller, die 7 + switches kan bedienen met het ene databyte van 7 bits! Maar + helaas kozen de MIDI-ontwerpers voor deze ruimte-vretende + oplossing. + + Zoals gezegd zijn de waarden 00h t/m 3Fh gelijk aan 'uit' en + 40h t/m 7Fh gelijk aan 'aan', maar dat heeft niet iedere + fabrikant begrepen. Verreweg het veiligst is het dus alleen + de waarden 00h (voor 'uit') en 7Fh (voor 'aan') te + gebruiken. + + De 5 switches in willekeurige volgorde zijn: + + + 4 0 H : D A M P E R P E D A L + + Dit is het sustain-pedaal van een piano. Wanneer deze + controller aan staat, wordt de toon niet meer uitgezet en + blijft dus eeuwig (in principe, tenminste) doorklinken. + + + 4 1 H : P O R T A M E N T O + + Inmiddels weet dus iedereen wat portamento is en kan ik hier + volstaan met de mededeling, dat deze controller dus het + portamento aan- en uitzet. + + + 4 2 H : S O S T E N U T O + + Sostenuto is in principe gelijk aan het Damper pedaal, met + dat verschil, dat het Damper-(oftewel sustain-)pedaal ook + die tonen, die later aangezet worden aanhoudt en het + sostenuto-pedaal alleen die tonen, die al aanstonden voordat + dit pedaal (controller) wordt aangezet, blijft aanhouden. + + + 4 3 H : S O F T P E D A L + + Aangezien een goede piano twee pedalen heeft (en een hele + goede zelfs drie, maar dat terzijde) regelt deze controller + het tweede pedaal, het soft-pedaal. Dit pedaal dempt het + geluid, zoals eenieder die ooit achter een piano gezeten + heeft (en natuurlijk ook gespeeld; alleen zitten levert bij + een piano weinig geluid op, uitzonderingen daargelaten) + weet. Voor die twee overblijvers: Ik kan hier wel een + uitgebreid verhaal gaan ophangen over de werking van dit + pedaal, maar verder dan de opmerking, dat het geluid minder + scherp klinkt, kom ik toch niet. Mocht u zich nog geen + indruk kunnen maken van dit effect, dan resteren er twee + mogelijkheden: 1) achter een piano gaan zitten en + uitproberen; of 2) (altijd de beste oplossing; ook voor alle + andere controllers) uitproberen via MIDI! + + + 4 5 H : H O L D 2 + + Deze controller dupliceert het sustain-pedaal wanneer er + tegelijk twee functies gebruikt moeten worden om een noot + aan te houden. Persoonlijk ben ik nog maar weinig + instrumenten tegengekomen, die deze controller herkennen. + + - De tekst wordt vervolgd in de volgende submenu-optie - + + + + - Dit is het vervolg van de tekst - + + M I D I C U R S U S + + + 7 - B I T S C O N T I N U E C O N T R O L L E R S + + Dit zijn de continue controllers, die niet via MSB en LSB + geregeld worden (hoewel ik al eerder opgemerkt heb, dat ik + persoonlijk nog geen instrument ben tegengekomen, dat de LSB + van die 14-bits continue controllers herkent...) maar + slechts 1 controller en dus 1 databyte genoeg vinden. Deze + zijn: + + + 50h T/M 53h: GENERAL PURPOSE CONTROLLERS 5 T/M 8 + + Naast de 14-bits controllers, die per fabrikant verschillen, + zijn er ook 4 7-bits controllers, die per fabrikant + verschillen. Elke fabrikant mag deze controllers naar eigen + goeddunken invullen; tussen verschillende instrumenten hoeft + dus geen herkenning op te treden, wanneer deze controllers + gebruikt worden. Misverstanden zijn echter wel te + verwachten: wanneer de ene fabrikant met controller 50h de + felheid van zijn display regelt (het is maar een + voorbeeld...) en een ander met controller 50h de leslie, + kunnen er nogal leuke effecten ontstaan, wanneer deze twee + instrumenten doorgekoppeld zijn! Denk in vergelijking maar + eens aan een rasechte Amsterdammer, die afzakt naar + Maastricht: Wat-ie al verstaat (dat zal wel niet veel zijn) + verstaat-ie waarschijnlijk nog verkeerd ook! + + + 5 B H T / M 5 F H : E F F E C T S + + Met deze 5 controllers worden 5 verschillende + effectprocessoren aangestuurd; deze zijn achtereenvolgens: + + - 5Bh: External effects depth (meestal een soort echo) + - 5Ch: Tremolo depth (om de mate van tremolo te regelen) + - 5Dh: Chorus depth (om de mate van chorus te regelen) + - 5Eh: Celeste (oftewel detune) depth + - 5Fh: Phaser depth (om het geluid 'uit fase' te zetten) + + Voor die enkeling, die nu het idee krijgt, dat ik weinig + informatie over dit onderwerp geef: Deze effecten zijn zo + apart, dat ze uitleggen eigenlijk afbreuk doet aan de + duidelijkheid; je moet ze horen om ze te begrijpen... En + bovendien zijn ze slechts sporadisch gebruikt, dus echt + belangrijk zijn ze niet (voordat ik de GS-kenners over me + heen krijg: Ja, op controllers 5Bh en 5Dh kom ik in het + GS-verhaal nog apart terug!). + + + 60h EN 61h: DATA INCREMENT EN DATA DECREMENT + + Via controller 06h/26h was het mogelijk data te versturen + naar aparte controllers. Welnu met de controllers 60h en 61h + is het mogelijk deze data respectievelijk met 1 te verhogen + of te verlagen. Net zoals bij controller 06h/26h al gezegd + hebben deze controllers voornamelijk invloed op de: + + + 62h T/M 65h: ON- EN GEREGISTREERDE CONTROLLERS + + Omdat de MIDI-ontwerpers een hekel hadden aan een eindig + aantal controllers, verzon men de geregistreerde (64h en + 65h) en de ongeregistreerde (62h en 63h) controllers. Het + verschil tussen deze twee is weer heel eenvoudig: De + geregistreerde zijn standaard, de ongeregistreerde zijn weer + per fabrikant anders. Verder zijn ze volstrekt hetzelfde + opgebouwd: + + De tweede databytes geven nu geen waarde aan maar een + volgende reeks controllers, waarbij de hoogste van elk paar + (bij de geregistreerde dus 65h, bij de ongeregistreerde dus + 63h) de MSB regelt en de laagste van elk paar (64h + respectievelijk 62h) de LSB. Het aantal controllers wordt in + ��n klap uitgebreid met 16384 nieuwe controllers! Bovendien + worden bij deze zgn. RPN (geregistreerde) en NRPN + (niet-geregistreerde) w�l zowel de MSB als de LSB verwacht! + + De waarde van de gekozen controller wordt achteraf veranderd + met behulp van de DATA-controllers (06h en 26h voor de + absolute invoer en 60h en 61h voor de relatieve invoer). + + Een voorbeeld, voor diegenen die naar duidelijkheid snakken: + + Om NRPN-controller MSB=00h/LSB=16h de waarde 54h te geven op + MIDI-kanaal 14, dient u alsvolgt de volgende bytes naar uw + instrument te sturen: + + BDh (B=Control Change; D=kanaal 14) + 63h (MSB van het NRPN eerst) + 00h (waarde van het MSB) + + BDh + 62h (LSB van het NRPN) + 16h (waarde van het LSB) + + BDh + 06h (DATA-invoer) + 54h (waarde van wijziging van NRPN 00h/16h) + + Zou de waarde nu een 14-bits getal geweest moeten zijn, dan + zou ook Controller 26h gebruikt hebben moeten worden en zou + het MIDI-event er alsvolgt uitgezien hebben: + + BDh 63h 00h BDh 62h 16h BDh 06h 04h BDh 26h 54h + + Voor diegenen die de 04h niet thuis kunnen brengen: Dit + slaat nergens op en is slechts bedoeld als voorbeeld. De + waarde die met dit laatste voorbeeld wordt uitgezonden, is: + + binair: &B00001001010100 + hexadecimaal: &H0454h + decimaal: 1108 + + Welke controller er nu veranderd is, kan ik natuurlijk niet + zeggen, daar dit (in tegenstelling tot de RPN-controllers) + bij de NRPN-controllers bij elk instrument anders is. Het + betreft hier ook maar een voorbeeld van het gebruik van de + NRPN- en RPN-controllers. + + De RPN-controllers zijn dus wel geregistreerd en voor die + grapjassen, die nu denken: "Ha, laat hem maar eens alle + 16384 controllers behandelen", kan ik antwoorden: Wie het + laatst lacht, lacht het best, want momenteel zijn er van de + 16384 geregistreerde controllers slechts 3 geregistreerd! + Deze zijn achtereenvolgens: + + MSB 00h/LSB 00h: PITCHBEND SENSITIVITY + + Met behulp van deze RPN-controller kan men aangeven hoeveel + noten een toon moet wijzigen bij een volledige uitslag van + het Pitch-bend-wiel. Het MSB van de data (06h) geeft het + aantal halve noten aan, het LSB het aantal honderdste van + een noot. + + MSB 00h/LSB 01h: FINE TUNING + + Hiermee kunt u uw instrument heel fijnschalig afstemmen: + Wanneer zowel MSB als LSB van de waarde 00h is, is uw + instrument 1 volledige halve noot verlaagd; is de MSB en LSB + daarentegen allebei 7Fh, dan is uw instrument een halve noot + verhoogd. Het gouden midden ligt bij MSB 40h en LSB 00h. Met + behulp van deze controller kunt u dus in 8192 stappen uw + instrument een halve toon verlagen en in 8191 stappen uw + instrument een halve toon verhogen! + + MSB 00h/LSB 02h: COARSE TUNING + + Gelijk aan FINE TUNING maar veel grofschaliger: Nu kunt u uw + instrument 64 halve noten verlagen en verhogen! Het midden + ligt uiteraard bij MSB=40h en LSB=00h. + + + M O D U S B O O D S C H A P P E N + + Poeh, poeh, we zijn er bijna: Als laatste onderdeel van de + Control changes worden nog even snel de 7 zgn. + modusboodschappen behandeld: Deze zijn achtereenvolgens: + + + R E S E T A L L C O N T R O L L E R S + + Wanneer de volgende MIDI-event wordt uitgezonden: + + Bxh 79h 00h + + Worden op het gewenste MIDI-kanaal (vul voor x een getal + tussen 0h en Fh in) in principe alle controllers van 00h t/m + 78h, de Pitchbend en de Aftertouch weer teruggezet op hun + beginwaarde. Ik zeg duidelijk in principe, want in de + praktijk worden over het algemeen maar een paar controllers + teruggezet. De fabrikant bepaalt namelijk zelf welke + controllers gereset worden en naar welke waarde ze gereset + worden... + + + L O C A L C O N T R O L + + Met de volgende MIDI-event: + + Bxh 7Ah 00h + + Wordt de local control afgezet. Wanneer als tweede databyte + in plaats van een 00h een 7Fh wordt uitgezonden, wordt deze + aangezet. Duidelijk toch... + + "Uhm, ben ik weer... Wat is Local Control eigenlijk?" + + Local Control regelt de verbinding tussen toetsenbord en + toongenerator. Wanneer Local Control aanstaat, wordt elke + toets, die op het toetsenbord wordt aangeslagen �n naar de + MIDI-out �n naar de toongenerator gestuurd, zodat er (als er + op de MIDI-out ook een instrument aangesloten is) twee + geluiden klinken. Staat nu de Local Control af, dan is de + verbinding tussen toetsenbord en toongenerator verbroken. + Elke toets, die nu aangeslagen wordt, wordt w�l naar de + MIDI-out gestuurd, maar wordt niet meer door het instrument + gespeeld. Daarentegen worden wel alle noten, die via MIDI-in + binnenkomen gewoon gespeeld. Het is alsof uw keyboard of + synthesizer is gesplitst in een apart commandotoetsenbord + (in Engels: Masterkeyboard) en een toongenerator. Wilt u in + dat geval toch geluid krijgen uit uw keyboard/synthesizer, + zult u de MIDI-out met de MIDI-in moeten verbinden! (PAS OP: + Staat Local Control aan, dan wordt dit geintje door diverse + fabrikanten ten strengste afgeraden!) + + + A L L N O T E S O F F + + Deze MIDI-boodschap (Bxh 7Bh 00h) zet alle tonen, die nog + aanstaan op het betreffende kanaal in ��n keer uit. Alleen + wanneer het sustain-pedaal aan staat (controller 40h) + behoren de tonen aan te blijven staan. In de praktijk blijkt + dit echter niet zo te zijn. Sommige fabrikanten houden zich + er netjes aan, anderen zetten ook dan alle noten uit. + + + O M N I O N / O F F ; P O L Y E N M O N O + + De volgende MIDI-events: + + Bxh 7Ch 00h (Omni mode off) + Bxh 7Dh 00h (Omni mode on) + Bxh 7Eh 00h (Mono mode on) + Bxh 7Fh 00h (Poly mode on) + + hebben invloed op de diverse MIDI-modi (enkelvoud: + MIDI-modus). Als enige overeenkomst zetten ze allemaal ook + alle noten uit. Voor de rest zijn deze MIDI-modi hopeloos + verouderd; vrijwel geen enkel hedendaags produkt maakt nog + gebruik hiervan. Dat wil geenszins zeggen, dat (zoals ik al + eens meegemaakt heb) deze MIDI-events als vervanging voor de + gewone ALL NOTES OFF gebruikt mogen worden! + + Voor de ge�nteresseerden: + MIDI kent 4 modi: + + 1) Omni on, poly + Het instrument accepteert alle voice-boodschappen over welk + kanaal dan ook en zal alle tonen aanzetten (tenzij het + instrument een polyfonie-grens heeft). + + 2) Omni on, mono + Het instrument accepteert alle voice-boodschappen over welk + kanaal dan ook, maar zal slechts ��n toon tegelijk laten + horen (speciaal voor oude, monofone synthesizers). + + 3) Omni off, poly + Het instrument accepteert alleen die voice-boodschappen, die + via hetzelfde kanaal komen als de OMNI OFF boodschap. Verder + zullen wel alle tonen, die via dat kanaal worden gestuurd + gespeeld worden (tenzij er een polyfonie-grens is). + + 4) Omni off, mono + Alleen die voice-boodschappen die via het, met behulp van + OMNI OFF, geselecteerde kanaal verstuurd worden, worden + gespeeld, maar nooit meer dan ��n tegelijk. Deze modus is + speciaal bedoeld voor MIDI-gitaar-spelers. Elke snaar op + zo'n gitaar correspondeert met een MIDI-kanaal. Op die + manier kan de gitaar-speler met behulp van zijn 6 snaren 6 + verschillende instrumenten aansturen. + + + S L O T + + Poeh, we zijn dan toch bij het einde van dit verhaal + gekomen. Zoals u wellicht is opgevallen, valt over de + Control Changes veel, heel veel te vertellen. Desondanks heb + ik alles slechts summier behandeld (enkele uitzonderingen + daargelaten). Voor diegenen, die willen gaan experimenteren + staat op deze diskette een BASIC-programma, dat via de Music + Module van Philips laat horen wat het effect is van elke + besproken controller. Gebeurt er op een gegeven moment + niets, dan ondersteunt uw instrument deze controller niet. + RUN't u het programma en er gebeurt helemaal niets, dan + dient u een Music Module, MIDI-kabels of een MIDI-instrument + te kopen en/of deze naar behoren met elkaar te verbinden + (MIDI-out naar MIDI-in). + + Ik wens u nog veel MIDI-plezier en tot een volgende keer... + + Ruud van Gestel diff --git a/sunrise_special/7/Music Module naar 256k.md b/sunrise_special/7/Music Module naar 256k.md new file mode 100644 index 0000000..f2ea999 --- /dev/null +++ b/sunrise_special/7/Music Module naar 256k.md @@ -0,0 +1,65 @@ + M U S I C M O D U L E N A A R 2 5 6 K + + + Voor de mensen met twee rechterhanden wordt hieronder + beschreven hoe je je Music Module kunt uitbreiden naar 256 + kB samplegeheugen. Het zal nog veel even duren voordat de + nieuwe versie van MoonBlaster die dit ondersteunt er zal + zijn maar er is in ieder geval al de schitterende demo + Unknown Reality van NOP met schitterende lange samples. + + Uiteraard is Stichting Sunrise niet aansprakelijk voor + eventuele fouten die ontstaan naar aanleiding van het + uitvoeren van deze uitbreiding. + + Nodig: + + - Philips Music Module + - 2 geheugen-IC's type 44C256 + - Soldeerbout van ongeveer 30 Watt + - Soldeertin + - 20 cm dun draad + + Voor het gemak noemen we de 2 geheugen-IC's IC-A en IC-B. + + 1) Maak bij IC-A de volgende doorverbindingen: + + pen 1 aan pen 11 pen 2 aan pen 12 + pen 13 aan pen 18 pen 14 aan pen 19 + + 2) Maak bij IC-B de volgende doorverbindingen: + + pen 2 aan pen 7 pen 8 aan pen 18 + pen 9 aan pen 19 + + 3) Verbind nu de volgende pinnen van IC-A en IC-B: pen 3, 4, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 20. + + 4) Zoek naar IC-8 in de Module en verbind de volgende + pennen van IC-B aan IC-8: + + IC-B IC-8 + pen 12 aan pen 10 + pen 3 aan pen 3 + pen 4 aan pen 4 + pen 6 aan pen 5 + pen 7 aan pen 7 + pen 8 aan pen 6 + pen 9 aan pen 12 + pen 10 aan pen 8 + pen 11 aan pen 11 + pen 13 aan pen 13 + pen 14 aan pen 9 + pen 15 aan pen 1 + pen 17 aan pen 15 + pen 20 aan pen 16 + + 5) Maak als laatste de volgende doorverbindingen op de Music + Module zelf: pen 16 van IC-A naar pen 8 van IC-2 en pen 9 + van IC-2 naar pen 36 van IC-10. + + 6) Maak de Module dicht en test deze bijvoorbeeld met + Unknown Reality van NOP. + + Bron: MAD Nieuwsbrief 6/94 + Met dank aan MSX Avengers Doetinchem diff --git a/sunrise_special/7/Nogmaals BDOS routines.md b/sunrise_special/7/Nogmaals BDOS routines.md new file mode 100644 index 0000000..3ba88c1 --- /dev/null +++ b/sunrise_special/7/Nogmaals BDOS routines.md @@ -0,0 +1,497 @@ + N O G M A A L S B D O S R O U T I N E S + + V O O R P R E T T I G E F I L E H A N D L I N G + + + Op Sunrise Special #4 staan twee artikelen met bijbehorende + listing van mijn hand over interfacing met de BDOS en disk + foutafhandeling onder DOS1. Geen commentaar was mijn deel. + Ik bedoel dat niemand die op dat moment even wat beter op de + hoogte was dan mijzelf zich goed genoeg voelde om mij mede + te delen dat er wat gevaren aan de routines kleven die ik in + de artikelen niet genoemd heb. Ik doel daarbij op het + wisselen van diskettes tijdens het lezen en schrijven van + komplete files. Lees ook het artikel op de vorige + submenu-optie. + + Ik heb de eerder gepubliceerde routines herschreven. Dat heb + ik gedaan om de error handler te debuggen en omdat ik tegen + de beperkingen van de routines aangelopen ben. Om het + geheugen even op te frissen: + + - Er kon maar ��n file tegelijkertijd open zijn + - De maximale handelbare filelengte was 64 kB + + Beide beperkingen zijn voor demo's en kleine utilities niet + erg vervelend, maar ik liep er tegen aan toen ik wat + ingewikkelde file-akties moest uitvoeren op meerdere files + tegelijkertijd. Het was dus tijd om het nog eens over te + doen waarbij beide beperkingen tot het verleden zouden + horen. + + Ik heb mij bij de ontwikkeling van de routines laten + inspireren door de ANSI-C standaard. De namen van de + routines kloppen niet met deze standaard, maar de + mogelijkheden komen redelijk overeen. + + Het doel van de routines is om 'dom' lees en schrijfwerk van + en naar diskettes, harddisks en wat je nog maar meer kunt + verzinnen wat eenvoudiger te maken. Op zich is het interface + van de BDOS naar de gebuiker goed (ook al is het al zo oud + dat Fred Flintstone het zich nog goed kan herinneren), maar + tijdens praktisch gebruik stoot je toch op wat zaken die + extra aandacht verdienen. + + Probeer je bv. een file van 1234 bytes in te lezen door een + random access block read van &H4000 bytes te doen dan gaat + dat wel goed, maar de call komt terug met de BDOS error code + A = 1. Wat moet je daar nu mee? Is er wat fout gegaan of is + dit juist een teken dat het goed ging? Als je er bij een + blockread voor zorgt dat er niet voorbij het End Of File + wordt gelezen, dan krijg je de foutmelding ook niet en is + het 'probleem' opgelost. Zo zijn er nog veel meer dingen die + door wat simpele testjes te doen, het leven van de + programmeur wat aangenamer kunnen maken. + + "Heeft die sukkel nu eindelijk DOS2 al eens ontdekt?", hoor + ik je zeggen. Welnu, ik ben een waanzinnig voorstander van + DOS2, maar ik vind het toch wat ver gaan om bij bv. spellen + en demo's (die niet uitsluitend voor de turbo R zijn) te + gaan eisen dat je DOS2 moet hebben. Daarom werken ook deze + routines nog gewoon met FCB's en zijn file-handles, + environment strings en sub-directories niet ge�mplementeerd. + Dat wil natuurlijk niet zeggen dat deze routines niet onder + DOS2 draaien. + + + D E F U N K T I E S + + Ik noem hier nu eerst even de funkties met hun aanroep etc. + waarna ik wat dieper op dit nieuwe ontwerp zal ingaan. + + ; BDOS fileshell routines for secure file loading and saving + ; File: BDOSR2.ASM V3.00 + ; By: Savage '94 (Fuzzy Logic) Last update: 29-07-94 + + ENASLT: EQU &H24 + PRINTC: EQU &HA2 + F##ERR: EQU &HF323 ; Double pointer to error routine + BDOS: EQU &HF37D + VDPBF1: EQU &HF3DF + VDPBF2: EQU &HFFE7-8 + + ; Jumpvectors + JP FINSTL + JP FRESET + JP FOPEN + JP FBLKRD + JP FCREAT + JP FBLKWR + JP FCLOSE + JP FSEEK + JP GETDIR + JP CHNDSK + JP DRVSTP + + ; Install BDOS fileshell + ; In : A (See BIOS rout 24H) + ; A must contain the settings for PAGE 1 (SLOT/SUBSLOT) + ; Out: Cy, on error + FINSTL: + + Deze routine moet worden aangeroepen voordat van de andere + routines gebruik gemaakt kan worden. In tegenstelling tot de + oude situatie wordt de BDOS entry nu niet meer afgebogen. + Het aanroepen van FINSTL: heeft verder geen gevolgen voor de + BDOS en andere routines zullen dus geen last van deze + installatie hebben. + + Bij invoer moeten in register A de slot en subslot + instellingen van PAGE 1 staan. Dit is nodig omdat de + DISK-ROM tijdens de error handler vrolijk op PAGE 1 aktief + staat en die moet door de error handler weer verwijderd + worden. + + + ; Reset BDOS fileshell + ; Out: Cy, on error + FRESET: + + Deze routine moet als laatste aangeroepen worden voordat met + iets anders begonnen wordt. In tegenstelling tot bij de oude + situatie is het gebruik van de BDOS door andere programma's + die niet van deze routines gebruik maken tussen een aanroep + naar FINSTL: en FRESET: niet langer aan beperkingen + gebonden. In de oude situatie werd een eventueel openstaande + file nog even gesloten. Nu wordt dat niet meer gedaan, maar + wordt alleen een waarschuwing gegeven dat er nog file(s) + open staan. + + + ;Set new 'disk error' handler and 'change disk' handler + INIERR: + + Deze routine wordt door de diskroutines aangeroepen voor ze + daadwerkelijk fysiek met de diskdrive aan de slag gaan. + Binnen deze funktie worden de BDOS error handler en de + 'change drive' hook van de BDOS afgebogen naar een eigen + routine. Nu hoor ik mensen al weer klagen dat dit een call + naar de BDOS alleen maar trager maakt en die mensen hebben + daarin wel gelijk. Deze vertraging is echter zo onmeetbaar + klein dat het de moeite van de overpeinzing niet waard is. + + + ;Reset disk handlers + EXIERR: + + Deze routine wordt na een fysieke aktie met de diskdrive + aangeroepen om de oude situatie van de BDOS error handler en + drive hook te herstellen. Zodoende zijn deze entries bv. + tussen een aanroep naar FOPEN: en FBLKRD: niet naar eigen + routines afgebogen. + + + ; Open a file + ; In : IX, Pointer to FCB + ; HL, Pointer to filenamestring (11 or 13 bytes long) + ; Out: Cy, on error + FOPEN: + + Bij aanroep van FOPEN: en FCREAT: hoeft van het 37 bytes + lange FCB bij invoer niets ingevuld te zijn. In assembly kan + dit FCB dus als volgt gedefinieerd worden. + + FCB: DS 37 + + In de filenamestring van 11 of 13 bytes staat de filenaam + van de file waar de aktie op uitgevoerd moet worden. In + assembly kan deze eenvoudig als volgt gedefinieerd worden. + + FLNAM1: DM "filename","ext" + FLNAM2: DM "A:filename","ext" + FLNAM2: DM "b:FiLeNaMe","ExT" + + In het eerste geval wordt de huidige drive (0) in het FCB + ingevult worden. In het tweede geval wordt specifiek drive + A: (1) in het FCB ingevuld en dat geldt ook voor B: (2). Een + ongeldige driveletter resulteert in een "File not found" of + "Cannot create" error bij resp. FOPEN: en FCREAT: Het maakt + niet uit of de string in kleine of hoofdletters wordt + ingevuld. + + + ; Read a block from the current fileposition + ; In : IX, Pointer to valid FCB + ; DE, Blocklength + ; HL, Loadaddress (not between 0x4000 and 0x7FFF) + ; Out: Cy, on physical load error + ; else, HL = the number of bytes actually read + FBLKRD: + + FBLKRD: zet zelf het DMA adres en controleert daarna of de + blokgrootte wel kan, door deze te vergelijken met de afstand + tussen de filelengte en het random record nummer. Indien het + blok niet past wordt de blokgrootte automatisch aangepast. + + + ; Create a file + ; In : IX, Pointer to FCB + ; HL, Pointer to filenamestring (11 or 13 bytes) + ; Out: Cy, on error + FCREAT: + + Zie ook FOPEN: + + + ; Write fileblock + ; In : IX, Pointer to valid FCB + ; DE, Blocklength + ; HL, Startaddress + ; Out: Cy, on error (File will be closed and deleted) + FBLKWR: + + De enige situatie waarin deze routine met een Cy terug komt + is als de gebruiker een (A)bort heeft gegeven, of als de + disk vol is. + + + ; Close file + ; In : IX, Pointer to FCB + ; Out: - + FCLOSE: + + Alleen files waarin geschreven is MOETEN met FCLOSE: + afgesloten te worden. + + + ; Fseek places the fileptr (random record number) on a + ; specified position + ; In : IX, Pointer to a valid FCB + ; HLDE, 32-bit offset value (HL = HIword) + ; A, 0 = Seek from the beginning of the file + ; 1 = Seek from the current position (curr_pos + + , offset) + ; 2 = Seek from EOF (EOF - offset) + ; Out: Cy, if the new offset is beyond EOF or A has an + ; invalid value + FSEEK: + + FSEEK: controleert of de opgegeven offset wel binnen de file + ligt en verandert (indien dit het geval is) het random + record number in het opgegeven FCB. De routine behandelt de + ingevoerde offset altijd als een positief getal. Negatieve + offsets leveren dus (meestal) een error op. + + + ; Read dir from disk + ; In : IX, Pointer to FCB + ; DE, Buffer for dir. (112*32+1 bytes) + ; HL, Directory search mask address + ; Out: Cy, HI then no files found + GETDIR: + + Vanaf register DE zal de directory van de disk in het + geheugen staan. Elke entry is 32 bytes lang en het einde kan + gevonden worden door te checken op een filenaam die met de + waarde 255 begint. + + + ; CHNDSK Set new drive + ; Request for same drive as current one is ignored !! + ; In: A, drive number (0=A: 1=B: etc.) + CHNDSK: + + Zie ook de verklarende tekst verderop. + + + ; Stop the diskdrive motor + DRVSTP: + + Zie ook de verklarende tekst verderop + + + ; BDOS error handler [system routine] + ; In: nothing + ; Out: nothing + DSERPT: DW ERRCDE ;Pointer to error code + ERRCDE: + + + ; Standard disk error handler + ; Request Abort or Retry input from the user + ABORET: + + ; 5 byte disk error hook + ; Out: A, "a" then abort disk action + ; "r" then retry last disk action + ; Remark: This hook can be used to include a customized + ; error handler + H.DERR: JP ABORET + DW 0 + + + ; Change disk query (hooked on &HF24F) + ; [BDOS system routine] + ; In : A, driveletter (in ASCII) + CHDSKQ: + + Deze routine moet het terugkeeradres van de aanroepende CALL + van de stack POPpen (de tweede POP AF in de listing) om te + voorkomen dat de BDOS ook nog eens een tekst print. + + - Deze tekst wordt vervolgd in de volgende submenu-optie - + + + + - Dit is het tweede gedeelte van de tekst - + + V E R V O L G B D O S + + + D E A A N P A S S I N G E N + + Een hele belangrijke aanpassing vind ik het feit dat het + BDOS entry point of &HF3DF niet langer direkt wordt + afgetapt. Hierdoor zullen andere routines die niet van het + bestaan van deze routines afweten er ook geen last van + hebben. Het lijkt mij dat deze aanpassing vooral de + betrouwbaarheid verhoogt. Daarnaast worden de BDOS error + handler en de 'change drive' hook per funktie ge�nstalleerd + en aan het eind weer verwijderd. Samengevat is het hele BDOS + systeem dus alleen afgetapt tijdens de executie van ��n van + deze routines. Dit is erg belangrijk als je tussendoor nog + andere programma's hebt die ook van de BDOS gebruik maken, + maar niet van deze routines. + + + L O S S E F C B S + + De andere belangrijke aanpassing is het feit dat nu een + eigen FCB aan de routines moet worden meegegeven. Dat lijkt + op het eerste gezicht een nadeel (meer invoerparameters), + maar het betekent wel dat er nu eenvoudig met meerdere files + tegelijkertijd gewerkt kan worden. + + + M A X F I L E L E N G T E 4 G B + + Het feit dat de max. filelengte waar nu mee gewerkt kan + worden 4GB is, lijkt op het eerste gezicht overbodig. Dat + verandert echter op het moment dat je n�t eventjes wat meer + dan 64kB wilt saven. De oude routines laten je dan hopeloos + in de steek. + + + R A N D O M F I L E A C C E S S + + Random file access is HEEL grappig. Wat sommige mensen niet + weten is dat random access op files niet alleen betekent dat + je zomaar overal binnen de bestaande file mag beginnen met + lezen of schrijven, maar dat er op een random access file + zowel lees als schrijfakties uitgevoerd mogen worden. Open + bv, een bestaande file met FOPEN: en niemand zal je + weerhouden om als eerste aktie met FBLKWR: een blok geheugen + in deze file te dumpen. Volkomen legaal, erg grappig en (op + PC's althans) een veel gebruikte methode om een harddisk als + virtueel geheugen te gebruiken. + + + D E R O U T I N E F S E E K : + + FSEEK: is een routine die in ANSI-C ongewijzigd hetzelfde + is. Het maakt het verplaatsen van het Random Record Number + (ook wel filepointer genoemd) even eenvoudig als het + wijzigen van het DMA adres. Het nut blijkt bij een nog door + mij uit te brengen cruncher waarbij ik nadat de komplete + file gecrunched en weggeschreven is, nog een header aan het + begin van de file moet invullen waar al wel ruimte voor + gereserveerd is. + + + D E R O U T I N E C H N D S K : + + De routine CHNDSK: in de oude routines is volledig + incompatible met de BDOS. Dat betekent dat een diskwissel + met deze routine niet aan de BDOS wordt doorgegeven en vice + versa. Nu is CHNDSK gewoon een aanroep van BDOS funktie 14 + en werkt het wel goed. + + Hierbij moet opgemerkt worden dat deze BDOS funktie niet + direkt bij aanroep om een nieuwe drivenummer vraagt. Dat + gebeurt pas bij de volgende aktie op die drive. Let hier een + beetje op i.v.m. spellen waar je niet te pas en te onpas + change disk meldingen wilt hebben. Je kunt het dan beter op + de oude manier doen waarbij het drivenummer in de FCB's + altijd 0 is. + + Vb: + + ; Stel de huidige drive is A: + LD A,(&HFCC1) ;BASIC ROM aktief + CALL FINSTL + + LD IX,FCB1 + LD HL,FLNAM1 + CALL FOPEN ;Open TEST.DAT op A: + JP C,FRESET ;Sukkel voor de computer !! + + LD A,1 ;Drive B: !!! (0 = A: etc.) + CALL CHNDSK + + LD IX,FCB2 + LD HL,FLNAM2 + CALL FCREAT ;Create TEST.CPY op B: + JP C,FRESET ;Nog meer sukkels + CALL FCLOSE + JP FRESET ;Wat een enorme file nietwaar? + + FCB1: DS 37 ;File op drive A: + FCB2: DS 37 ;File op drive B: + + FLNAM1: DM "a:test ","dat" + FLNAM2: DM "b:test ","cpy" + + De call naar CHNDSK: heeft niet tot gevolg dat de melding + "Insert disk for drive ..." in beeld komt. Dat gebeurt pas + binnen FCREAT:. Wordt dit 'programma' twee keer achter + elkaar opgestart dan wordt de tweede keer eerst om drive A: + gevraagd omdat tijdens het verlaten van het programma drive + B: nog ingesteld is. + + Deze manier van drivewisseling is echter erg leuk omdat + mensen met twee drives geen melding op hun scherm zullen + krijgen omdat er gewoon van twee drives gebruik gemaakt + wordt. Deze routine is eenvoudig uit te breiden tot een (te) + eenvoudig kopieerprogramma. Doordat de BDOS nu konstant op + de hoogte is van diskwisselingen, mag WEL van disk gewisseld + worden tijdens lees- en schrijfakties. De totale leesaktie + moet natuurlijk wel op dezelfde disk uitgevoerd worden en + dat laatste geldt natuurlijk ook voor de schrijfaktie. + + + D E R O U T I N E D R V S T P : + + DRVSTP: laat de drivemotor stoppen. Hier zijn in theorie + meerdere manieren voor. Ikzelf heb lange tijd de entry in de + BDOS zelf gebruikt omdat die onmiddellijk resultaat oplevert + en relatief snel is. Meneer Stefan Boer deelde me laatst + echter mede dat dit niet op alle MSX'en werkt (zucht, daar + gaan we weer). Het blijkt dat bepaalde knutselaars een + afwijkende DISK-ROM hebben waarbij die entry op een ander + adres terecht is gekomen. Ik ben nog nooit zo'n ding tegen + het lijf gelopen, maar gezien het feit dat veiligheid voor + alles gaat heb ik de routine dus maar weggeknikkerd. + + De vervanging die simpelweg 255 keer &HFD9F aanroept is de + oudste oplossing om de drivemotor te laten stoppen. De + andere methode waarbij eerst de 'motor delay counter' op 1 + wordt gezet waarna eenmalig &HFD9F wordt aangeroepen blijkt + volgens sommige bronnen ook niet altijd te werken en dus heb + ik ook die voorlopig overboord gezet. + + Er is mij nu wel op het hart gedrukt dat de nu + ge�mplementeerde routine de beste is omdat hij op ALLE MSX- + en werkt, maar ik heb um op mijn SONY eens aan het werk + gezet. Disassemblering van de routine op &HFD9F leert mij + dat er op een SONY helemaal geen drive stop wordt + aangeroepen en dat de drive volledig automatisch stopt (dat + was echter geen nieuws). Op een SONY is het 255 keer + aanroepen van &HFD9F dus niets meer dan een domme + vertraging. Kan iemand mij dan misschien vertellen wat er in + hemelsnaam op een Philips of turbo R gebeurt, want deze + drivestop lijkt me een beetje onzinnig. [Op een turbo R + stopt de drive ook automatisch, alleen op een (!#$%&) + Philips is het �berhaupt nodig om de drive stop te zetten.] + + + I N T E R R U P T S A A N E N U I T + + Tijdens een BDOS aanroep bij de oude routines wordt de + V_BLANK interrupt volledig uitgezet. Dat was innertijd om + mensen die nog steeds een trage DISK-ROM in hun SONY hebben + van enige snelheid te voorzien. Nu zit dit er niet meer in + om interruptproblemen bij bv. een aanroep naar BIOS funktie + &H9F te voorkomen. + + + T E N S L O T T E + + Ik heb deze routines al redelijk stevig getest en ik heb tot + op dit moment nog geen gekke onverklaarbare dingen + meegemaakt. Het aantal vernielde diskjes is ook 0, en dat + blijft hopelijk ook zo, zolang een komplete file + schrijfaktie maar op ��n en dezelfde disk wordt uitgevoerd. + Diskwisselingen die hier tussendoor komen mogen dus wel als + je gebruik maakt van de 'change drive' routine omdat de BDOS + er dan rekening mee houdt. + + Ik ben er persoonlijk wel happy mee. Beperkingen worden er + niet meer opgelegd en andere routines die wel van de BDOS + gebruik maken, maar niet van deze routines, hebben er + ab-so-luut geen last van. Het is zelfs zo dat er met bv. + FBLKRD: gelezen kan worden uit een file die niet met FOPEN: + geopend is. Dat alles in combinatie met een zeer eenvoudige + BDOS interfacing voor het lezen en schrijven van files maakt + deze routines voor mij in ieder geval onmisbaar. + + Alex van der Wal diff --git a/sunrise_special/7/Score in ML.md b/sunrise_special/7/Score in ML.md new file mode 100644 index 0000000..e47e4f4 --- /dev/null +++ b/sunrise_special/7/Score in ML.md @@ -0,0 +1,394 @@ + S C O R E I N M L + + + Bij het maken van een spel loop je al snel tegen het + probleem op dat de grootste getallen die je in ML + fatsoenlijk kunt gebruiken (16 bits getallen) te klein zijn + om fatsoenlijk een score of iets dergelijks in op te slaan. + Bij Xak II is je maximale experience bijvoorbeeld 65535, en + dat staat gewoon niet professioneel. Voor leken is het + vreemd dat er zo'n vreemde bovengrens is (voor hen zou + bijvoorbeeld 99999 een veel logischere bovengrens zijn) en + degenen die een beetje ML kennen zien meteen dat ze bij + MicroCabin gewoon een 16 bits getal hebben gebruikt om de + experience bij te houden. + + Het afdrukken van een 16 bits getal is al redelijk + ingewikkeld (zie hiervoor de artikelen in MCCM, ik heb er + ook al eens aandacht aan besteed al was dat een minder + ingenieuze routine), maar als je grotere getallen wilt, 32 + bits bijvoorbeeld, dan wordt het helemaal een hele tour, + vooral om het ook nog een beetje snel te doen. En als je + bijvoorbeeld wilt dat de score snel kan oplopen, dan is zo'n + 32 bits afdrukroutine simpelweg te traag. Hoe goed je ook + kunt programmeren. + + + B C D + + Deze problemen heb je niet als je gebruik maakt van het BCD + formaat. BCD is een afkorting voor Binary Coded Decimal, een + codering waarmee je toch met decimale getallen kunt werken + op een computer die eigenlijk alleen geschikt is voor + binair, octaal en hexadecimaal. Dit is een 'native' datatype + van de Z80 processor, het wordt ondersteund door een aantal + vlaggen en instructies. Ik kom hier later nog op terug. + + Het BCD formaat werkt heel simpel, je zet gewoon in elke + nibble ��n cijfer van 0-9. De BCD notatie van het getal + 321456 is dus #32 #14 #56. De verzameling rekenroutines van + MSX-BASIC (bekend onder de naam MathPack) werkt ook met het + BCD formaat, waarbij het is uitgebreid met een exponent. + Voor scores e.d. is dat echter niet nodig en dus werken we + kale BCD, zonder exponent. + + + D A A + + Zoals ik al zei is BCD een native datatype van de Z80, en is + het dus relatief eenvoudig om routines voor het verwerken + van getallen in BCD formaat te schrijven. De Z80 instructie + die het meeste ingewikkelde werk uit handen neemt is DAA, + wat staat voor Decimal Adjust Accumulator. DAA zal + 'rekenfouten' die ontstaan bij optellen en aftrekken (en + alleen daarbij!) corrigeren zodat het resultaat ook weer in + BCD formaat staat. Ik zal dit verduidelijken met een + voorbeeld: + + LD A,#07 + ADD A,#07 + + A bevat nu de waarde 14, oftewel #0D. Het juiste antwoord + moet echter #14 zijn, want we werken met BCD formaat. Door + nu gewoon een instructie DAA te geven zal de Z80 deze + 'rekenfout' zelf corrigeren!!! Dus: + + LD A,#08 + ADD A,#05 + DAA + + A bevat nu de waarde #13! De Z80 heeft voor dit corrigeren + een aantal speciale vlaggen, waarvan je je misschien al + afvroeg waarom ze er zijn omdat je ze nooit gebruikt, er + zijn zelfs geen voorwaardelijke JP/JR/CALL/RET instructies + voor. Bit 1 van het F register is de N-vlag, die wordt gezet + als er een aftrekking plaatsvindt. De correctie is bij een + optelling namelijk anders dan bij een aftrekking. Bit 4 van + het F register is de H-vlag, de Half carry. Deze wordt gezet + als er een halfcarry optreedt van de low nibble naar de high + nibble van A. + + In bovenstaand voorbeeld is N niet gezet (er is opgeteld) en + H wel, er is immers een halfcarry opgetreden (5 + 8 is + groter dan 10). Hierdoor weet de Z80 dat hij 6 bij het + resultaat moet optellen. Dat klopt, want 13 + 6 = 19 = #13. + Nu een voorbeeld met aftrekken: + + LD A,#42 + SUB #07 + DAA + + Hier is weer een half carry, maar nu is er afgetrokken. #42 + - #07 = #3B. Aan de vlaggen kan de Z80 zien dat hij 6 moet + aftrekken om te corrigeren, en inderdaad #3B - #06 = #35 en + dat is precies het gewenste antwoord. Aan de half carry kan + de Z80 dus zien of er een correctie nodig is, en aan de + aftrekvlag kan hij zien of er 6 moet worden afgetrokken of + worden bijgeteld. Maar op zich hoef je dit niet eens te + weten om met DAA te kunnen omgaan. + + + S C O R E D A T A T Y P E + + We gaan nu een speciaal score datatype defini�ren. De + representatie, BCD zonder exponent, hebben we al, nu hebben + we nog een aantal operaties (lees: routines) met dit + datatype nodig. Hieronder volgen deze routines. Voor het + gemak gaan we ervan uit dat de lengte van de getallen altijd + even is, zodat er niet met halve bytes gewerkt hoeft te + worden. Bij alle routines wordt in B de lengte in bytes + meegegeven. + + + ; SCORE.GEN + ; Routines voor werken met getallen in BCD-formaat van + ; willekeurige lengte + ; Enige beperking is dat lengte altijd even moet zijn + ; Door Stefan Boer + + ; Waarschuwing: alle routines mogen AF, HL, BC, DE + ; veranderen!!! + + ; InitGetal + ; In : HL = ^getal, B = lengte/2 + ; Uit: getal is 0 + + Op zich een overbodige routine maar voor de volledigheid + staat hij erbij. Met ^ bedoel ik "pointer naar", dezelfde + notatie die bij Pascal gebruikt wordt. Deze routine maakt + dus het getal met lengte B waar HL naar wijst gelijk aan 0. + De implementatie is zeer eenvoudig: + + InitGetal: LD (HL),0 + INC HL + DJNZ InitGetal + RET + + + ; AssignGetal + ; In : HL = ^bron, DE = ^doel, B = lengte/2 + ; Uit: doel = bron + + Ook dit is weer een routine die er voor de volledigheid bij + zit. HL wijst naar het te kopi�ren getal, DE naar de + bestemming. De implementatie is weer triviaal: + + AssignGetal: LD C,B + LD B,0 + LDIR + RET + + + ; AddGetal + ; In : HL = ^getal1, DE = ^getal2, B = lengte/2 + ; Uit: getal1 = getal1 + getal2, carry als uitkomst te + ; groot en dan 999... + + Tel het getal waar DE naar wijst op bij het getal waar HL + naar wijst, en zet de uitkomst op de plaats waar HL naar + wijst. Dit is de eerste routine waarbij we DAA gaan + gebruiken. + + AddGetal: PUSH HL + PUSH BC + CALL MovePointers + + We bewaren HL en B even omdat we bij een te grote uitkomst + het hele getal met 9's moeten vullen. De routine + MovePointers verplaatst HL en DE naar het einde van het + getal. Dat is nodig omdat we van rechts naar links moeten + werken bij optellen, zoals je je misschien nog wel zult + herinneren van de lagere school. + + OR A ; wis carry + AddGetal_2: LD A,(DE) + ADC A,(HL) + DAA + LD (HL),A + DEC HL + DEC DE + DJNZ AddGetal_2 + + Dit is de feitelijke optelling. De cijfers worden per + groepje van twee (er zitten twee cijfers in ��n byte) bij + elkaar opgeteld, DAA zorgt dat ook het resultaat weer BCD + formaat is en we gebruiken ADC om de carry mee te nemen. + + POP BC + POP HL + RET NC + AddGetal_3: LD (HL),#99 ; overflow + INC HL + DJNZ AddGetal_3 + SCF + RET + + Als er geen carry is zijn we klaar, is er wel een carry dan + past de uitkomst niet, we vullen het getal met 9's en aan de + carry kan het programma zien dat er een overflow was. + + ; Zet DE en HL op einde van getallen + + MovePointers: PUSH BC + DEC B + JR Z,MovePointers_2 + MovePointers_1: INC DE + INC HL + DJNZ MovePointers_1 + MovePointers_2: POP BC + RET + + Als het getal 6 cijfers lang is (B=3), moeten we de pointer + 3-1=2 plaatsen opschuiven. Vandaar de DEC B. + + + ; SubGetal + ; In : HL = ^getal1, DE = ^getal2, B = lengte/2 + ; Uit: getal1 = getal1 - getal2, carry bij negatieve + ; uitkomst en dan 000... + + Aftrekken gaat net zo als optellen: + + SubGetal: PUSH HL + PUSH BC + EX DE,HL + CALL MovePointers + + Aangezien er geen SBC A,(DE) bestaat is het hier handiger + als DE en HL zijn verwisseld, vandaar de EX DE,HL. + + OR A ; wis carry + SubGetal_2: LD A,(DE) + SBC A,(HL) + DAA + LD (DE),A + DEC HL + DEC DE + DJNZ SubGetal_2 + + Ook hier hetzelfde als bij optellen, alleen wordt er nu + natuurlijk SBC gebruikt in plaats van ADC. + + POP BC + POP HL + RET NC + CALL InitGetal ; underflow + SCF + RET + + Voor het vullen met nullen hebben we al een routine dus die + gebruiken we ook. Omdat het vaak voorkomt dat je een getal + alleen maar met ��n hoeft te verhogen of verlagen heb ik + daar speciale routines voor. + + ; IncGetal + ; In : HL = ^getal, B = lengte/2 + ; Uit: getal = getal + 1, carry als getal te groot + + IncGetal: CALL MovePointers + IncGetal_1: LD A,(HL) + CP #99 + JR NZ,IncGetal_2 + XOR A + LD (HL),A + DEC HL + DJNZ IncGetal_1 + SCF + RET + IncGetal_2: ADD A,1 + DAA + LD (HL),A + OR A + RET + + Deze routine vervangt elke byte #99 vanaf rechts in #00 + totdat er een byte ongelijk is aan #99. Die wordt dan eentje + verhoogd (daarbij treedt nooit een carry op!), gecorrigeerd + met DAA en klaar is kees. Let op: in plaats van de ADD,1 mag + NIET door INC A worden vervangen! Want dan werkt DAA niet + meer goed. Decrease gaat net zo: + + ; DecGetal + ; In : HL = ^getal, B = lengte/2 + ; Uit: getal = getal - 1, carry als getal gelijk aan 0 + + DecGetal: CALL MovePointers + DecGetal_1: LD A,(HL) + AND A + JR NZ,DecGetal_2 + LD A,#99 + LD (HL),A + DEC HL + DJNZ DecGetal_1 + SCF + RET + DecGetal_2: SUB 1 + DAA + LD (HL),A + OR A + RET + + Getallen vergelijken is ook een belangrijke en vaak + voorkomende operatie: + + ; CompareGetal + ; In: HL = ^getal1, DE = ^getal2, B = lengte/2 + ; Z- en C-flag worden net als bij CP gezet + + De vlaggen worden dus hetzelfde gezet als bij CP. Dat is + niet alleen logisch maar ook nog eens het makkelijkst voor + de implementatie: + + CompareGetal: EX DE,HL + CompareGetal_1: LD A,(DE) + CP (HL) + RET NZ + INC HL + INC DE + DJNZ CompareGetal_1 + RET + + Ook hier weer een EX DE,HL omdat er nu eenmaal wel een CP + (HL) is en geen CP (DE). Zo gauw er een ongelijke byte + gevonden wordt zijn we klaar (RET NZ). Als de hele lus + doorlopen wordt zijn de getallen gelijk en is de Z-flag nog + gezet door de laatste CP. + + Tot slot nog de routine waar het allemaal omdraait: het + afdrukken! Deze routine is, zeker als je hem vergelijkt met + een routine voor het afdrukken van 16- of 32-bits getallen, + zeer snel. Bovendien zit je hier niet aan een maximale + lengte vast, nou ja, de maximale lengte is 512 cijfers! + + ; WriteGetal + ; In : HL = ^getal, B = lengte/2 + ; Getal wordt afgedrukt, routine PrintChar moet bekend zijn, + ; met als invoer A: ASCII van character, + ; mag HL, BC, DE wijzigen + + De manier van afdrukken ligt erg voor de hand, hierbij wordt + gewoon eerst het hoogste nibble genomen, naar het laagste + nibble geschoven, omgerekend naar ASCII en afgedrukt, en + daarna wordt het laagste nibble afgedrukt. + + WriteGetal: LD A,(HL) + EXX + PUSH AF + AND #F0 + RRCA + RRCA + RRCA + RRCA + ADD A,"0" + CALL PrintChar + POP AF + AND #0F + ADD A,"0" + CALL PrintChar + EXX + INC HL + DJNZ WriteGetal + RET + + Voor PrintChar kun je je eigen routine invullen om karakters + op het scherm te zetten. En hiermee is de verzameling + routines voor ons eigen BCD formaat compleet. + + + V O O R D E L E N E N N A D E L E N + + Tot slot nog even de voordelen en nadelen ten opzichte van + 16- of 32-bits getallen op een rij. + + Voordelen: + + - de lengte van de getallen is vrijwel onbeperkt (maximaal + 512 cijfers) + - de snelheid van het afdrukken is zeer snel + + Nadelen: + + - optellen en aftrekken gaat iets minder snel, hoewel het + meestal geen snelheidsproblemen zal opleveren + - vermenigvuldigen en delen is zeer moeilijk te programmeren + + Het snelheidsverlies bij optellen/aftrekken wordt zeker goed + gemaakt door het veel snellere afdrukken. Vermenigvuldigen + en delen gaat met 16- en 32-bits getallen ook al niet + makkelijk, maar hierbij is het helemaal ingewikkeld. Maar + vermenigvuldigen en delen heb je weinig nodig in spellen, en + als het toch nodig is kun je het altijd met herhaald + optellen/aftrekken programmeren. Niet echt snel maar het + werkt wel. + + Stefan Boer diff --git a/sunrise_special/7/Toetsenborden en microbiologie.md b/sunrise_special/7/Toetsenborden en microbiologie.md new file mode 100644 index 0000000..9c61e49 --- /dev/null +++ b/sunrise_special/7/Toetsenborden en microbiologie.md @@ -0,0 +1,113 @@ + T O E T S E N B O R D E N E N + + M I C R O B I O L O G I E + + + Ik durf te beweren dat de Sony HB-F___ serie MSX2 computers + de beste toetsenborden voor MSX computers hebben. Die weke + Philips en Panasonic troep kan mij niet in vuur en vlam + zetten, noch kan ik mij lovend over beide inferieure + ramplanken uitspreken (alhoewel er toch wel aan te wennen + is). + + U merkt het al, deze jongen heeft (nog) een Sony; een erg + oude Sony overigens. Wij praten hier over het tijdperk van + voor Methusalem toen ik met mijn in de jeugdjaren bijelkaar + geslijmde kwartjes en stuivers (mijn grootouders waren + altijd al wat ouderwets zonder besef van inflatie) tot + trotse bezitter maakte van wat toen de cr�me de la cr�me van + MSX technologie was. + + Zelden heeft een toestenbord zo moeten lijden als onder mijn + regime. Heus, als er een Amnesty International voor + toetsenborden zou bestaan dan zou ik bovenaan de jaarlijkse + zwarte lijst staan als uiterst gemene tiran die zijn toetsen + jaar in jaar uit meedogenloos weet te onderdrukken + (doordrukken zou een beter woord zijn). + + Maar helaas, zelfs Japanners kunnen niet iets maken dat + blijvend is. Mijn toetsenbord begon het te begeven, na jaren + van trouwe dienst. Het begon met een haperende BACKSPACE + toets (erg lastig overigens) en eindigde in een dramatische + huilbui toen ik op een gegeven moment alleen nog met een + hamer de BACKSPACE kon bewegen van positie te veranderen. + + Tijd voor een schoonmaakbeurt. Met goed fatsoen de onderkant + verwijderd om daarna met de mond vol tanden te staan. Nog + nooit had ik zoveel (geborgde) schroefjes op 1 print + bijelkaar gezien. Vol goede moed toch maar de + schoevendraaier gepakt en aan het werk gegaan. Dat bleek + niet mee te vallen, mijn fysiotherapeut beschuldigde me er + later van dat ik een notoir bierdrinker moest zijn om op + zo'n leeftijd al zulke versleten polsen te kunnen hebben. + + Affijn, de print liet uiteindelijk los en toen maakte ik de + kapitale fout door het hele zootje eens om te draaien. Mijn + mooie zwarte bureaublad lag plotseling bezaaid met stukjes + Alex. Duidelijk waren perioden van roos en nagelbijten in + mijn prille pubertijd zichtbaar als sedimentlagen in een + rivierbedding. Enkele reeds uitgestorven insektensoorten + bleken in gemummificeerde vorm tevoorschijn te komen en de + heren biologen zijn nog steeds bezig om alle nieuw ontdekte + mossen, schimmels en zwammen te klassificeren. Ik snap nu + wat men bedoeld met de uitspraak dat de computerbusiness + 'leeft'. + + Het is op zijn minst grappig dat de natuur zo'n grote + invloed op de computer industrie heeft. Wist u bijvoorbeeld + dat de term 'debuggen' stamt uit de jaren 50 toen men een + overklaarbare fout constateerde in een van de toen gangbare + buizen computers. Na heel veel speurwerk vond men het + probleem. Het bleek te gaan om een kevertje ('bug' in het + Engels) dat kortsluiting in de bedrading had veroorzaakt. + Laat u dus geen oor aannaaien als iemand meedeeld dat een + 'debugger' een programma is. In werkelijkheid is het een + hoog opgeleide ingenieur die zich in onmogelijke bochten + wringt op zoek naar gebraden torretjes in kamergrote + computers. + + Toen deze macabere wereld al zijn geheimen aan mijn + bureaublad had blootgegeven heb ik het maar eens kennis + laten maken met een afvalbak. Ik had al eens gehoord dat er + soms de meest wilde dingen in toetsenborden worden gevonden, + maar dat het zo erg is; nee dat had ik niet gedacht. Ik kan + niet zeggen dat ik het vreemd vond dat de BACKSPACE toets + het niet meer deed. + + Overijverig dat ik was maakte ik de tweede kapitale blunder; + ik haalde de kontaktspray tevoorschijn. De print was nl. + voorzien van een aangebrachte zwarte substantie (ik vermoed + een koolstofmix) op de kontaktpunten voor de toetsen. De + toetsen blijken een soort membramen die door het indrukken + van een toets naar buiten worden geforceerd. Aan het + uiteinde van zo'n membraam hangt een klein zwart rondje dat + het feitelijke kontakt tussen de kontaktpunten op de print + maakt. Deze zwarte rondjes zijn van een nog niet nader + ge�dentificeerde materie. Ik vond die van de BACKSPACE toets + wat smerig en bedolf hem derhalve uit pure frustratie in + kontaktspray. + + Dat had ik beter niet kunnen doen. Enig doorfluiten + (elektrotechnische term voor het meten van weerstand) leerde + me nl. dat de zwarte rondjes niet geleidend waren, maar dat + er een substantie op zit die dat wel is. Deze substantie had + ik bij de BACKSPACE toets dus weggespoten met het + oplosmiddel in de kontaktspray. Om deze fout te herstellen + heb ik een CODE toets opgeofferd (waar je toch 2 van hebt) + om deze met de BACKSPACE toets te vervangen. + + Later had ik echter een ideetje. Ik schroefde de ramplank + weer open (daar gaan je polsen) en heb toen een uiterst + miniem klein stukje zilverfolie op het zwarte rondje van de + niet langer werkende CODE toets geplakt. Dat bleek genoeg om + de toets weer beter te maken dan hij ooit geweest is. Let + natuurlijk wel op dat de lijm alleen aan de goede kant van + de zilverfolie komt, want er zijn bij mijn weten niet zoveel + elektrisch geleidende lijmen. + + Kortom, de toetsenborden van SONY's zijn uitstekend te + repareren. Ik wens potenti�le reperateurs veel succes bij + hun speurtocht door de sedimentlagen van hun lichamelijke + geschiedenis. + + Alex van der Wal diff --git a/sunrise_special/7/VDP Cursus 11.md b/sunrise_special/7/VDP Cursus 11.md new file mode 100644 index 0000000..5e6f653 --- /dev/null +++ b/sunrise_special/7/VDP Cursus 11.md @@ -0,0 +1,334 @@ + M S X 2 / 2 + V D P C U R S U S ( 1 1 ) + + + P A L E T S P L I T + + We gaan deze keer een voorbeeld van een zogenaamde + paletsplit behandelen. Dit is een screensplit, waarbij het + palet wordt veranderd bij de screensplit. Hierdoor kunnen er + dan bijvoorbeeld 32 kleuren tegelijk op het scherm in SCREEN + 5. Eerst maar even wat theorie. + + + P A L E T A A N S T U R E N + + De VDP heeft 16 paletregisters, die worden aangeduid met P#0 + t/m P#15. Deze paletregisters kunnen niet direct worden + beschreven, en het is helemaal niet mogelijk om palet- + registers uit te lezen. + + De paletregisters kunnen alleen indirect worden beschreven, + en wel door eerst het palet te selecteren door het nummer + naar R#16 te schrijven en vervolgens de paletdata naar Port + #2 te sturen (I/O poort &H9A). + + De paletdata bestaat uit twee bytes, waarvan slechts 9 bits + van belang zijn. Drie bits voor rood, drie bits voor blauw + en drie bits voor groen. De twee bytes met paletdata zijn + als volgt opgebouwd: + + MSB 7 6 5 4 3 2 1 0 LSB + 0 ----R---- 0 ----B---- 1e byte + 0 0 0 0 0 ----G---- 2e byte + + Let op, want de volgorde is niet R,G,B zoals bij de COLOR= + instructie in BASIC maar R,B,G. De handigste notatie om + paletbytes weer te geven is door de eerste byte in hex te + zetten en de tweede gewoon in decimaal, dus zo: + + &HRB,G + + Waarbij R, B en G zoals we gewend zijn lopen van 0-7. De + kleur met R=3, B=7 en G=1 wordt dus: + + &H37,1 + + Tot slot geef ik nog even een voorbeeld van de complete + procedure die moet worden gevolgd om de BASIC instructie + COLOR=(13,7,2,5) in ML te maken: + + DI + LD A,13 + OUT (&H99),A + LD A,16+128 + OUT (&H99),A ; selecteer P#13 + EI + LD A,&H75 ; R=7, B=5 + OUT (&H9A),A + LD A,2 ; G=2 + OUT (&H9A),A + + De DI en EI instructies zijn nodig omdat de interrupts + altijd uit moeten staan als we naar een VDP register + schrijven. Bij het schrijven van de paletregisters is dit + alleen nodig als er op de interrupt ook iets met de + paletregisters zou kunnen worden gedaan. In dat geval moet + de EI verhuizen naar het einde van de routine. + + Tot slot moeten we nog weten dat de paletpointer (R#16) + automatisch wordt verhoogd na het ontvangen van twee palet + bytes van Port #2 en daarbij na P#15 weer verder gaat bij + P#0. Als we bij bovenstaand voorbeeld dus ook nog kleur 14 + zouden willen veranderen, kunnen we volstaan met het + schrijven van de twee paletbytes naar &H9A. + + + S C R E E N S P L I T + + De theorie over het palet is nu in voldoende mate behandeld, + maar voor een paletsplit hebben we ook een screensplit + nodig. Ik prefereer de zogenaamde "polling screensplit". Dit + zegt u waarschijnlijk weinig, tenzij u de tekst over + Interrupt Service Routines op Sunrise Special #2 hebt + gelezen. Daar wordt namelijk uitgelegd wat polling is. + + Er zijn twee manieren om een screensplit te detecteren. De + eerste manier is door de VDP de opdracht te geven een + interrupt te genereren zodra hij bij een bepaalde beeldlijn + is bij de schermopbouw. De computer springt bij de interrupt + naar adres &H38 en komt zo vanzelf bij de hook &HFD9A + terecht. Als je die hook afbuigt met je eigen routine kun je + de screensplit verder afhandelen. + + Er is echter een veel simpeler manier, die bovendien sneller + reageert op de screensplit, en dat is polling. Bij polling + wacht je gewoon totdat de VDP bij de juiste lijn is + aangeland met de schermopbouw. Als je dit een beetje slim + uitkient neemt het ook nog eens minder processortijd in + beslag dan de interruptmethode. Bij de interruptmethode + worden namelijk alle registers op de stack gePUSHt, en wordt + er flink wat heen en weer gesprongen voordat de computer + eindelijk bij jouw screensplitroutine is. Bij polling is dat + allemaal niet nodig. + + + S C R E E N S P L I T M E T P O L L I N G + + Hoe werkt nu zo'n screensplit met polling. Vrij eenvoudig. + Je moet het programma zo programmeren dat je per interrupt + werkt. Aan het begin zet je een HALT neer. Een HALT wacht op + een interrupt. Dit is normaal gesproken altijd de 50 of 60 + Hz interrupt, die optreedt als de VDP met de schermopbouw + bij lijn 212 is aangeland. HALT laat die interrupt eerst + uitvoeren, en daarna wordt er verder gegaan met het + hoofdprogramma. + + Heb je bijvoorbeeld de replayroutine van MoonBlaster aan + &HFD9F hangen, dan wordt de muziek dus eerst afgespeeld. Na + de HALT doe je de scherminstellingen voor het bovenste + gedeelte van het scherm. In dit geval is dat dus het naar de + VDP sturen van het palet voor het bovenste gedeelte. + + Vervolgens ga je andere dingen doen (bijvoorbeeld het + toetsenbord uitlezen, berekeningen doen, etc.), en je mikt + het ongeveer zo uit dat de computer daarmee klaar is als de + VDP met de beeldopbouw bij de screensplit is aangeland. + + Nu zet je de lijn voor de screensplit in R#19. De VDP zal nu + bit 0 van S#1 zetten zodra hij bij die lijn is. Je checkt + dus bit 0 van S#1 net zolang totdat het op 1 springt. Dan + stuur je het palet voor de onderste helft van het scherm + naar de VDP. Vervolgens heb je nog tijd om andere dingen te + doen. Als je er maar voor zorgt dat de computer weer op tijd + bij de HALT is. + + + M E E R D E R E S C R E E N S P L I T S + + Het grote voordeel van deze methode is dat meerdere + screensplits geen enkel probleem zijn. Gewoon nog een keer + het screensplitroutinetje erin zetten, alleen dan met een + andere lijn. + + Bij de interruptmethode wordt dit toch ingewikkelder, omdat + de computer bij elke interrupt (ook de 50/60 Hz interrupt!) + naar &HFD9A springt, zodat je in die routine eerst moet + uitzoeken welke screensplit het eigenlijk is. + + Genoeg theorie, we gaan gauw verder met het voorbeeld. Hier + komt de assemblerlisting, zoals gewoonlijk rijkelijk + voorzien van uitleg. + + + ; PALSPLIT.ASM + ; Voorbeeld paletsplit: 32 kleuren op het scherm + ; VDP Cursus Sunrise Magazine #6 + ; Stefan Boer 18/01/93 + ; (c) Ectry 1993 + + LINE: EQU 106 + + ORG &HD000 + DI + XOR A + OUT (&H99),A + LD A,16+128 + OUT (&H99),A ; P#0 selecteren + + + Hier wordt P#0 geselecteerd. Dit hoeven we slechts ��n keer + te doen, omdat we toch elke keer alle 16 paletregisters + beschrijven. Na afloop staat de paletpointer dan immers toch + weer op 0. Hierna begint de hoofdlus: + + + UPPER: EI + XOR A + CALL &HD8 ; spatiebalk testen + RET NZ + + + Door de routine GTTRIG op adres &HD8 aan te roepen met de + waarde 0 in het A register vragen we de status van de + spatiebalk op. Als de spatiebalk is ingedrukt wordt de + routine be�indigd. + + + HALT ; wacht op interrupt + + + Hier wordt op de interrupt gewacht, dit is dus de + 'screensplit' op lijn 212. + + + DI + LD HL,PALET1 ; palet voor bovenste helft + LD BC,&H209A ; 32 bytes naar poort &H9A + OTIR ; stuur palet naar VDP + + + De interrupts worden uitgezet, al is dat eigenlijk niet + nodig omdat er in de praktijk toch geen interrupts optreden. + Vervolgens wordt het palet met een OTIR instructie naar de + VDP gestuurd. Omdat we in dit voorbeeld verder toch niets te + doen hebben gaan we gelijk verder met de screensplitroutine. + + + LD A,LINE + OUT (&H99),A + LD A,19+128 + OUT (&H99),A ; lijn voor screensplit + + + Hier wordt de lijn voor de screensplit naar R#19 geschreven. + LINE is aan het begin van de listing met een EQU op 106 + gezet, dat is het midden van het scherm (want dat is 212 + lijnen). + + + LD A,1 + OUT (&H99),A + LD A,15+128 + OUT (&H99),A ; S#1 selecteren + NOP + NOP ; geef VDP tijd om data klaar + ; te zetten + LOWER: IN A,(&H99) ; lees S#1 + BIT 0,A ; test op screensplit + JP Z,LOWER ; lijn nog niet bereikt + + + We selecteren eerst S#1, zodat we die kunnen lezen door Port + #1 (poort &H99) te lezen. De twee NOPjes zijn nodig om de + VDP de kans te geven de juiste data op &H99 te zetten. + Vervolgens wachten we tot bit 0 van S#1 op 1 springt. Dan + weten we dat de VDP bij lijn 106 is aangeland. + + + LD HL,PALET2 ; palet voor onderste helft + LD BC,&H209A ; 32 bytes naar poort &H9A + OTIR ; stuur palet naar VDP + + + We sturen op de inmiddels bekende wijze het palet naar de + VDP. + + + XOR A + OUT (&H99),A + LD A,15+128 + OUT (&H99),A ; weer S#0 voor BIOS + + + Dit is belangrijk, voor de BIOS moet S#0 altijd zijn + geselecteerd. Om het BIOS zo snel mogelijk te houden wordt + er namelijk simpelweg IN A,(&H99) gebruikt om S#0 te lezen. + + + JP UPPER + + + En tot slot springen we weer naar de bovenste screensplit, + waar eerst nog even op de spatie wordt gecheckt. Nu nog de + paletten invullen: + + + ; palet voor bovenste helft van scherm + + PALET1: DB &H00,0,&H11,1,&H22,2,&H33,3 + DB &H44,4,&H55,5,&H66,6,&H77,7 + DB &H10,0,&H20,0,&H30,0,&H40,0 + DB &H50,0,&H60,0,&H70,0,&H77,0 + + ; palet voor onderste helft van scherm + + PALET2: DB &H00,0,&H01,0,&H02,0,&H03,0 + DB &H04,0,&H05,0,&H06,0,&H07,0 + DB &H00,1,&H00,2,&H00,3,&H00,4 + DB &H00,5,&H00,6,&H00,7,&H07,7 + + + De hier gegeven data is natuurlijk volslagen willekeurig, u + kunt hier zelf invullen wat u wilt. Deze assmblerlisting + staat als PALSPLIT.ASC op de diskette, geassembleerd onder + de naam PALSPLIT.BIN. + + + V O O R B E E L D + + In PALSPLIT.PMA zit het voorbeeldprogramma PALSPLIT.BAS, dit + programma tekent 2 maal 15 verticale balken in SCREEN 5 om + de routine uit te testen. Er zijn dan dus 31 kleuren + tegelijk op het scherm (30 balken + achtergrondkleur = + zwart). + + + N E T T E P A L E T S P L I T + + U zult bij het voorbeeld helemaal niets merken van de + paletsplit. Dit komt omdat de split ergens bij lijn 106 zit, + en daar zit alleen kleur 0. Ik heb kleur 0 express in beide + paletten hetzelfde gehouden, zodat de overgang niet te zien + is. + + Kijk maar eens wat er gebeurt als u kleur 0 wel verschillend + maakt, dan kun je duidelijk de screensplit zien zitten. Je + ziet ook dat hij trilt. + + Bij andere screensplits kun je de split wegwerken door op + een bit van een statusregister te checken dat aangeeft dat + de VDP begint met het opbouwen van de lijn. Omdat dat niet + precies klopt moet er dan ook nog een wachtlusje bij. + Waarschijnlijk kom ik daar in een later deel van de VDP + cursus nog wel eens op terug. + + Bij een paletsplit is de hier gebruikte oplossing echter + beter, het kost vrijwel geen moeite en je ziet de split + absoluut niet. Zorg dus dat kleuren die in het overloop- + gebied voorkomen in beide paletten hetzelfde zijn, dan zie + je niets van de paletsplit. + + + 5 1 2 K L E U R E N + + Ik denk dat het mogelijk is om met behulp van deze routine + alle 512 kleuren tegelijkertijd op het scherm te krijgen in + SCREEN 5, door gewoon het screensplitstuk een flink aantal + keren achter elkaar te zetten en voldoende verschillende + paletten toe te voegen. Ik heb het zelf nog niet geprobeerd, + misschien een andere keer. + + Veel succes met het experimenteren met deze routine en tot + de volgende keer. + + Stefan Boer diff --git a/sunrise_special/7/VDP Cursus 12.md b/sunrise_special/7/VDP Cursus 12.md new file mode 100644 index 0000000..0230be1 --- /dev/null +++ b/sunrise_special/7/VDP Cursus 12.md @@ -0,0 +1,314 @@ + M S X 2 / 2 + V D P C U R S U S ( 1 2 ) + + + Welkom bij het twaalfde deel van de inmiddels legendarische + VDP cursus. Ook deze keer gaan we weer een ML routine + bespreken. Dit keer is het een routine om tekst met een + grafische karakterset op het scherm te zetten in SCREEN 5. + De theorie die hiervoor nodig is is allemaal al aan bod + geweest, dus we beginnen meteen met de source. + + In dit voorbeeld gebruiken we een 6x8 karakterset, maar het + is heel eenvoudig om de routine aan te passen zodat + karakters van andere formaten worden gebruikt. Ik geef de + routine hier in de BASIC uitvoering, maar hij kan natuurlijk + ook gewoon in een puur ML programma worden gebruikt. + + + ; P R T E X T . A S M + ; Zet tekst op scherm in SCREEN 5 met COPY (font in page 3) + ; Aanroepen door coordinaten in te POKEn: + ; POKE &HD003,X : POKE &HD004,Y + ; en daarna U$=USR("tekst") + ; Door Stefan Boer, (c) Ectry 1993 + ; VDP Cursus Sunrise Magazine #7 + + ORG &HD000 + + JP PRTEXT + XCOOR: DB 0 + YCOOR: DB 0 + + + Dit ziet er misschien een beetje vreemd uit, maar dit is + gedaan om het aanroepadres en de adressen van de co�rdinaten + die moeten worden ingePOKEt standaard te houden. + + + PRTEXT: LD A,(DE) + LD B,A + INC DE + LD A,(DE) + LD L,A + INC DE + LD A,(DE) + LD D,A + LD E,L ; DE=startadres, B=lengte + + + Als je een ML routine vanuit BASIC aanroept met + + U$= USR(string) + + dan staat in het DE register het begin van de zogenaamde + "string desriptor". Deze string descriptor bestaat uit drie + bytes. De eerste is de lengte van de twee strings, de twee + andere bytes geven het beginadres in het geheugen staan. + Hier zetten wij het beginadres in DE en de lengte in B. + + + LD A,(XCOOR) + LD (COPDAT+4),A ; DX invullen + LD A,(YCOOR) + LD (COPDAT+6),A ; DY invullen + + + Hier worden de ingePOKEte co�rdinaten in de copydata + ingevuld. + + + PRINT: PUSH BC ; bewaar aantal karakters + LD A,(DE) ; haal teken + INC DE ; DE wijst naar volgende teken + SUB 32 ; eerste karakter is spatie + ADD A,A ; A=A*2 + LD C,A + LD B,0 ; LD BC,A + LD HL,CORTAB ; startadres coordinatentabel + ADD HL,BC ; bereken adres in tabel + + + We maken gebruik van een co�rdinatentabel omdat de routine + dan met elke willekeurige grafische karakterset kan worden + gebruikt. We trekken 32 van de ASCII code van het teken af + en vermenigvuldigen dat met twee. Vervolgens tellen we dit + bij het startadres van de tabel op en we hebben het adres in + de tabel waar de co�rdinaten van het desbetreffende teken + staan. + + + LD A,(HL) + LD (COPDAT),A ; SX invullen + INC HL + LD A,(HL) + LD (COPDAT+2),A ; SY invullen + + + Die co�rdinaten worden hier uit de tabel gehaald en in de + copydata gezet. Zoals we gewend zijn werken we weer met een + blokje copydata van 15 bytes. De benodigde gegevens (source, + destination, etc.) kunnen dan zonodig door het programma + worden veranderd en het uitvoeren van het commando door de + VDP is een kwestie van een simpele OTIR. + + + LD HL,COPDAT + LD BC,&H0F9B + WACHT: LD A,2 + CALL RDSTAT ; lees statusregister + BIT 0,A + JR NZ,WACHT + + + Eerst wachten we netjes totdat de VDP klaar is door op bit 0 + van S#2 te testen. Doen we dit niet, dan kan dat vreemde + effecten hebben. Zeker als de routine op een turbo R onder + R800 stand wordt gedraaid, omdat de kans dan groter is dat + de VDP nog niet klaar is met het kopi�ren van de vorige + letter als hij hier is aangeland. De data voor de OTIR + (HL=beginadres, B=aantal bytes, C=I/O poort) zetten we + alvast klaar. + + + DI + LD A,32 + OUT (&H99),A + LD A,17+128 + OUT (&H99),A + EI + OTIR ; voer copy uit + + + Hier schrijven we de waarde 32 naar R#17, hiermee selecteren + we het startregister voor het indirect registers schrijven + van de VDP. Met de OTIR wordt het blokje met copydata naar + Port #3 gestuurd, waardoor deze bytes netjes in de commando + registers (32 t/m 46) terecht komen en de VDP de letter naar + het scherm zal kopi�ren. + + + LD A,(COPDAT+4) ; oude DX + ADD A,6 ; volgende positie + LD (COPDAT+4),A ; nieuwe DX invullen + NXTKAR: POP BC + DJNZ PRINT + RET + + + Hier wordt er 6 bij de x co�rdinaat opgeteld, zodat de + volgende letter netjes naast deze komt te staan. De lus + wordt afgesloten met een DJNZ. + + + ; Statusregister lezen. In: A=register, Uit: A=data + + RDSTAT: DI + OUT (&H99),A + LD A,128+15 + OUT (&H99),A ; selecteer statusregister + NOP ; geef VDP tijd om data + NOP ; klaar te zetten + IN A,(&H99) + EX AF,AF + XOR A + OUT (&H99),A + LD A,128+15 + OUT (&H99),A ; selecteer S#0 + EI + EX AF,AF + RET + + + Dit is een standaardroutine voor het uitlezen van een + statusregister, dit zou u inmiddels zonder verdere uitleg + moeten kunnen begrijpen. + + + COPDAT: DB 0,0,0,3 ; SX en SY (page 3) + DB 0,0,0,0 ; DX en DY (page 0) + DB 5,0,7,0 ; NX en NY + DB 0,0 ; CLR en ARG + DB &B10010000 ; LMMM + + + Dit is het blok met copy data. De pages, grootte en het + commando zijn al ingevuld, door de routine wordt de source + (de letter op page 3) en de destination (waar komt de letter + op page 0) ingevuld. &B10010000 staat voor LMMM, Logical + Move VRAM to VRAM. + + Tot slot de co�rdinatentabel. Dit ziet er misschien een + beetje lang uit, maar het is met een BASIC programmaatje in + een wip aangemaakt. Deze tabel kunt u aanpassen voor elke + gewenste karakterset. + + + ; Coordinaten van ASCII 32 t/m ASCII 93 + + CORTAB: DB 0,197 ; + DB 6,197 ; ! + DB 12,197 ; " + DB 18,197 ; # + DB 24,197 ; $ + DB 30,197 ; % + DB 36,197 ; & + DB 42,197 ; ' + DB 48,197 ; ( + DB 54,197 ; ) + DB 60,197 ; * + DB 66,197 ; + + DB 72,197 ; , + DB 78,197 ; - + DB 84,197 ; . + DB 90,197 ; / + DB 96,197 ; 0 + DB 102,197 ; 1 + DB 108,197 ; 2 + DB 114,197 ; 3 + DB 120,197 ; 4 + DB 126,197 ; 5 + DB 132,197 ; 6 + DB 138,197 ; 7 + DB 144,197 ; 8 + DB 150,197 ; 9 + DB 156,197 ; : + DB 162,197 ; ; + DB 168,197 ; < + DB 174,197 ; = + DB 180,197 ; > + DB 186,197 ; ? + DB 192,197 ; @ + DB 0,205 ; A + DB 6,205 ; B + DB 12,205 ; C + DB 18,205 ; D + DB 24,205 ; E + DB 30,205 ; F + DB 36,205 ; G + DB 42,205 ; H + DB 48,205 ; I + DB 54,205 ; J + DB 60,205 ; K + DB 66,205 ; L + DB 72,205 ; M + DB 78,205 ; N + DB 84,205 ; O + DB 90,205 ; P + DB 96,205 ; Q + DB 102,205 ; R + DB 108,205 ; S + DB 114,205 ; T + DB 120,205 ; U + DB 126,205 ; V + DB 132,205 ; W + DB 138,205 ; X + DB 144,205 ; Y + DB 150,205 ; Z + DB 156,205 ; [ + DB 162,205 ; \ + DB 168,205 ; ] + + + V O O R B E E L D + + Zo, dat was de ML routine. Niet echt moeilijk denk ik. Hij + staat op de disk onder de naam PRTEXT.ASC. Om het uit te + testen gebruiken we het volgende BASIC programma: + + 100 ' PRTEXT voorbeeld + 110 ' Door Stefan Boer, 20/03/93 + 120 ' (c) Ectry 1993 + 130 ' Sunrise Magazine #7 VDP cursus + 140 ' + 150 SCREEN5:COLOR15,0,0:CLS + 160 CLEAR200,&HCFFF:DEFINTA-Z:BLOAD"PRTEXT.BIN": + DEFUSR=&HD000 + 170 OPEN"GRP:"AS1:SETPAGE,3:CLS:A=32:FORI=0TO192STEP6: + PRESET(I,197):PRINT#1,CHR$(A):A=A+1:NEXT: + FORI=0TO168STEP6:PRESET(I,205):PRINT#1,CHR$(A):A=A+1: + NEXT:SETPAGE,0 + 180 FORI=50TO150STEP20:READT$:POKE&HD003,128-3*LEN(T$): + POKE&HD004,I:U$=USR(T$):NEXT + 190 IFSTRIG(0)=0THEN190ELSEEND + 200 DATA "PRTEXT" + 210 DATA " " + 220 DATA "(C) ECTRY 1993" + 230 DATA " " + 240 DATA "VDP CURSUS" + 250 DATA "SUNRISE MAGAZINE #7" + + Dit staat ook op de disk onder de naam PRTEXT.BAS. De + geassembleerde ML file staat er ook op: PRTEXT.BIN. Samen + staan deze files in PRTEXT.PMA. + + Dit voorbeeld is niet bepaald spectaculair, omdat de + standaardkarakterset wordt gebruikt. Wel valt het op dat dit + een stuk sneller is dan OPEN"GRP:"AS1/PRINT#1. Het grote + voordeel hiervan is dat u elk gewenste formaat letters + (zelfs proportioneel als u de routine een klein beetje + aanpast!) kunt gebruiken, ook met meerdere kleuren! + + + T E N S L O T T E + + Een beetje korte tekst dit keer, maar dat hoop ik de + volgende keer goed te maken met een extra lange routine. + + Dit is een leuk voorbeeld om uit te breiden, ik noemde al + een andere (grotere) karakterset of proportioneel schrift. + Zet daarvoor achter de co�rdinaten in de tabel ook de + breedte van de letter, en tel dat getal op bij de oude DX. + + Veel plezier en tot de volgende keer! + + Stefan Boer diff --git a/sunrise_special/7/VDP Cursus 13.md b/sunrise_special/7/VDP Cursus 13.md new file mode 100644 index 0000000..97264b6 --- /dev/null +++ b/sunrise_special/7/VDP Cursus 13.md @@ -0,0 +1,477 @@ + M S X 2 / 2 + V D P C U R S U S ( 1 3 ) + + + Bijgelovige mensen moeten dit deel maar overslaan, maar dat + zou zonde zijn want ook dit deel is weer erg leerzaam. Deze + keer behandel ik een ML routine om SCREEN 5 naar SCREEN 8 om + te zetten. Hiervoor is de theorie nodig over het aansturen + van het VRAM en over de opslag van de schermen in het VRAM, + wat uitgebreid in eerdere delen is terug te vinden. Ik zal + het deze keer alleen kort nog even herhalen. + + + S C R E E N 5 N A A R 8 + + + SCREEN 5 en SCREEN 8 hebben dezelfde resolutie, namelijk 256 + bij 212 pixels. Op dat vlak dus geen problemen. Wat er + uiteindelijk moet worden omgezet zijn de kleuren. + + In SCREEN 5 wordt er gewerkt met 16 kleuren uit een palet + van 512, terwijl er in SCREEN 8 slechts 256 kleuren zijn, + die wel allemaal tegelijkertijd op het scherm kunnen worden + getoond. We moeten de 16 SCREEN 5 kleuren dus omrekenen naar + SCREEN 8 kleuren. Hierbij zal wel een klein verschil + ontstaan omdat in SCREEN 8 maar 256 van de 512 verschillende + kleuren precies kunnen worden nagemaakt. Van de overige + kleuren moeten we de kleur nemen die er het dichtst bij in + de buurt komt. + + + P A L E T + + Voor het palet in SCREEN 5 zijn er drie bits voor rood, drie + bits voor groen en drie bits voor blauw. Deze moeten naar de + paletregisters van de VDP worden geschreven (zie hiervoor + deel 1 van de cursus), maar kunnen niet worden gelezen. + + In MSX BASIC is dat opgelost door het palet ook nog eens in + het VRAM op te slaan. In SCREEN 5 staat deze kopie van het + palet vanaf adres &H7680. Omdat het palet 32 bytes lang is, + eindigt het op adres &H769F. Het palet kan bij een SCREEN 5 + plaatje dus als volgt worden meegesaved: + + BSAVE "FILENAAM.SC5",0,&H769F,S + + Als het plaatje weer wordt ingeladen kan het palet dan weer + worden teruggehaald met COLOR=RESTORE. Het palet wordt dan + van het VRAM naar de paletregisters van de VDP gekopieerd. + + De data vanaf adres &H7680 is als volgt opgebouwd: + + MSB 7 6 5 4 3 2 1 0 LSB + + &H7680 0 ----R---- 0 ----B---- palet #0 + &H7681 0 0 0 0 0 ----G---- + &H7682 0 ----R---- 0 ----B---- palet #1 + etc. + + Hierbij staat R voor de rode intensiteit, B voor de blauwe + intensiteit en G voor de groene intensiteit, dit alles 3 + bits dus tussen 0 en 7. + + + S C R E E N 8 K L E U R E N + + In SCREEN 8 is er geen palet, maar kan de kleur rechtstreeks + uit de opslag van het scherm in het VRAM worden afgelezen. + Elke byte is als volgt opgebouwd: + + MSB 7 6 5 4 3 2 1 0 LSB + + ----G---- ----R---- --B-- + + Hierbij staan R, G en B weer voor de rode, groene en blauwe + intensiteit. Het valt meteen op dat er voor blauw slechts + twee bits zijn, zodat dit maar een getal tussen 0 en 3 kan + zijn. Dit is de reden waarom een SCREEN 5 plaatje niet exact + kan worden geconverteerd naar SCREEN 8. + + + B I T M A P + + De opslag van de schermdata in het VRAM gaat bij SCREEN 5 en + 8 volgens de bitmap methode. Voor elk pixel zijn er een + aantal bits gereserveerd, waarin de informatie over dat + pixel staat. Elk pixel heeft z'n eigen bits, waardoor er + geen beperkingen zijn aan het aantal kleuren dat bij naast + elkaar liggende pixels mag worden gebruikt, zoals in + bijvoorbeeld SCREEN 2 en SCREEN 12. + + In SCREEN 5 wordt van elk pixel het paletnummer opgeslagen, + dit is een getal van 0-15 en daarvoor zijn dus 4 bits nodig. + In elke byte staan daarom twee pixels, waarbij het linker + pixel in de hoge nibble (bit 4-7) staat en het rechter pixel + in de lage nibble (bit 0-3). In SCREEN 8 zijn er 8 bits per + pixel nodig, dus staat er in elke byte het kleurnummer van + ��n pixel. + + Nu we alle benodigde informatie over de schermen hebben + kunnen we met de conversieroutine beginnen. Zoals gewoonlijk + is deze in WB-ASS2 geschreven, staat de source in ASCII op + de disk en heb ik de source uitgebreid van extra commentaar + en uitleg voorzien. + + Het inladen van het SCREEN 5 plaatje en het wegschrijven van + het SCREEN 8 plaatje laten we aan BASIC over, dit is + tenslotte geen diskcursus. Op de diskette vindt u in + SC5SC8.PMA een BASIC programma (SC5SC8.BAS), dat de ML file + (SC5SC8.BIN) inlaadt en zorgt voor het inladen en + wegschrijven van de grafische files. Ook de source zit + erbij. + + + ; S C 5 S C 8 . A S M + ; SCREEN 5 omzetten naar SCREEN 8 + ; Stefan Boer, april 1993 + ; (c) Ectry 1993 + ; Sunrise Magazine #8 + ; (c) Stichting Sunrise 1993 + + ; SCREEN 5 plaatje in SCREEN 8 inladen, met palet + ; SC8 plaatje wordt door routine over SC5 plaatje gezet + ; en kan worden gesaved met BSAVE"NAAM.SC8",0,54271,S + + ORG &HD000 + + LD A,(&HF342) ; RAM slot &H4000-&H7FFF + LD H,&H40 + CALL &H24 ; RAM op &H4000 + IN A,(&HFE) ; mapper poort &H8000-&HBFFF + LD (OLDMAP),A ; bewaar mapper instelling + LD A,3 ; selecteer ander RAM + OUT (&HFE),A + + + Op adres &HF342 staat de slot-ID byte van het RAM op + &H4000-&H7FFF (page 1). We gebruiken de BIOS routine ENASLT + (adres &H0024) om op adres &H4000 RAM te zetten in plaats + van de BASIC interpreter. We gebruiken dit RAM om tijdelijk + schermdata in op te slaan. + + Op &H8000 selecteren we een ander gedeelte van de mapper, + zodat het BASIC programma dat daar staat niet wordt + overgeschreven. I/O poort &HFE bepaalt welke mapperpage er + op adres &H8000 staat. + + + ; kopieer SCREEN 5 data van VRAM naar RAM + + LD HL,0 + LD C,0 ; VRAM lezen vanaf adres + CALL SETRD ; &H00000 (bitmap data) + + + De standaardroutine SETRD kennen we nog uit het begin van de + cursus. Deze routine stelt de VDP in om VRAM te lezen vanaf + het adres dat in HL en C staat, hierbij is bit 0 van het C + register het MSB (most significant bit) van het VRAM adres. + HL bevat de rest van het adres. Het beginadres van het + scherm in het VRAM is &H00000. + + + LD DE,&H4000 ; beginadres SC5 data in RAM + LD BC,27136 ; lengte SC5 data (128*212) + + COPY: IN A,(&H98) ; lees byte uit VRAM + LD (DE),A ; sla op in RAM + INC DE + DEC BC + LD A,B + OR C + JP NZ,COPY ; herhaal tot BC=0 + + + Hier wordt de SCREEN 5 data naar het RAM gekopieerd, vanaf + adres &H4000. Een scherm is 212 lijnen hoog en elke lijn + neemt 128 bytes in beslag (256 pixels, twee pixels per + byte), dus de totale lengte van een SCREEN 5 plaatje in het + VRAM is 27136 bytes. + + Met IN A,(&H98) wordt het VRAM gelezen. De VDP verhoogt + daarna zelf het leesadres, zodat de volgende keer + automatisch de volgende byte wordt gelezen. Dit wordt + herhaald totdat het hele plaatje in het RAM staat. + + LD A,B en daarna OR C is een truukje om te kijken of BC al + gelijk is aan 0. + + + ; kopieer palet data van VRAM naar RAM + + LD HL,&H7680 + LD C,0 ; VRAM lezen vanaf adres + CALL SETRD ; &H07680 (palet data) + + LD HL,PALET ; beginadres paletdata in RAM + LD B,32 ; lengte palet data + LD C,&H98 ; Port #0 (VRAM lezen) + INIR ; lees B bytes van poort (C) + ; ; en zet in RAM vanaf HL + + + Hier kopi�ren we de paletdata (die zoals we eerder hebben + gezien vanaf adres &H7680 in het VRAM staat) naar het RAM. + Het SCREEN 5 plaatje moet dus wel met palet zijn weggesaved. + + Met de instructie INIR worden B bytes gelezen van poort (C) + en vanaf (HL) in het RAM gezet. Bij het vorige gedeelte had + het weinig zin om deze instructie te gebruiken, omdat er + toen 27136 bytes moesten worden gelezen en er met INIR maar + maximaal 256 bytes per keer kunnen worden gelezen. Het palet + wordt dus vanaf (PALET) in het RAM gezet. + + [Nvdr. De tekst was langer dan 16 kB, u kunt verder lezen + door de volgende optie in het submenu te kiezen.] + + + + M S X 2 / 2 + V D P C U R S U S ( 1 3 ) + + + [Nvdr. Dit is het tweede gedeelte.] + + + ; Converteer palet naar SCREEN 8 kleuren + + LD B,16 ; 16 paletten om te rekenen + LD HL,PALET + LD DE,COLORS ; beginadres SC8 kleurentabel + PALCNV: LD A,(HL) ; lees eerste byte paletdata + AND &B01110000 ; alleen rood (bit 4-6) + RRCA + RRCA ; verplaats rood naar bit 2-4 + LD C,A + + + Dit is het moeilijkste gedeelte van de routine, hier rekenen + we de 16 paletkleuren om naar SCREEN 8 kleuren. We lezen + eerst een byte, en filteren alleen het rood eruit dat zoals + we eerder gezien hebben op bit 4-6 staat. In de SCREEN 8 + kleurcode moet het rood op bit 2-4 staan, we moeten dit dus + twee posities naar rechts verschuiven. Daarvoor gebruiken we + RRCA, deze instructie roteert het A register naar rechts. + Het resultaat wordt in C bewaart, zodat we later blauw en + groen erbij kunnen zetten. + + + LD A,(HL) + AND &B00000111 ; alleen blauw (bit 0-2) + SRL A ; verplaats blauw naar bit 0-1 + OR C + LD C,A ; rood en blauw samen + + + Op analoge wijze wordt hier het blauw toegevoegd. De + instructie SRL A schuift de bits in het A register een + plaatsje naar rechts, terwijl in bit 7 een 0 wordt gezet. We + kunnen hier geen RRCA gebruiken, omdat bit 0 dan in bit 7 + terecht zou komen, en dat is niet de bedoeling. Met OR C + worden rood en blauw samen in een byte gezet. + + + INC HL + LD A,(HL) + AND &B00000111 ; groen (bit 0-2) + RRCA + RRCA + RRCA ; verplaats groen naar bit 5-7 + OR C + + + Groen staat in de volgende byte. Dit moet eigenlijk 5 + plaatsen naar links worden verplaats, maar 3 plaatsen naar + rechts is natuurlijk precies hetzelfde en is korter. Nu + staat de complete SCREEN 8 kleurcode die overeenkomt met de + SCREEN 5 paletkleur in het A register. Het enige verschil is + dat de blauwe intensiteit nu minder nauwkeurig is. + + + LD (DE),A ; SC8 kleurcode naar tabel + INC HL + INC DE + DJNZ PALCNV + + + De zojuist berekende SCREEN 8 kleurcode wordt in de tabel + gezet, en zo worden alle 16 paletkleuren afgewerkt. We gaan + nu de feitelijke schermdata converteren. + + + ; converteer SCREEN 5 data naar SCREEN 8 + + LD HL,0 + LD C,0 + CALL SETWRT ; VRAM schrijven vanaf &H00000 + + + We beginnen weer met de VDP klaar te zetten voor een VRAM + actie, dit keer schrijven. Hiervoor gebruiken we SETWRT, de + tegenhanger van SETRD. Het SCREEN 8 plaatje wordt op adres 0 + gezet, dus gewoon over het SCREEN 5 plaatje heen. + + + LD DE,&H4000 ; SC5 data vanaf &H4000 in RAM + LD BC,27136 ; aantal te converteren bytes + CONVRT: PUSH BC + LD A,(DE) ; lees SC5 byte (2 pixels) + AND &HF0 ; linker pixel + RRCA + RRCA + RRCA + RRCA ; verplaats naar lage nibble + + + DE bevat het huidige adres in het RAM tijdens het omzetten + en BC het aantal nog te converteren bytes. Hier wordt een + SCREEN 5 byte uit het RAM opgehaald en wordt het linker + pixel eruit gehaald. Het paletnummer van dit pixel staat in + de linker nibble, en die verplaatsen we met 4 RRCA + instructies naar het rechter nibble. Nu kunnen we de + bijbehorende SCREEN 8 kleurcode uit de tabel halen: + + + LD HL,COLORS + LD C,A + LD B,0 + ADD HL,BC ; bereken plaats in tabel + LD A,(HL) ; haal kleurnummer uit tabel + OUT (&H98),A ; schrijf naar VRAM + + + Een ADD HL,A instructie bestaat niet, dus dat doen we via + een klein omweggetje. Tot slot wordt de byte naar het VRAM + geschreven met de OUT (&H98),A instructie. Nu nog het + rechter pixel: + + + LD A,(DE) + AND &H0F ; rechter pixel + LD HL,COLORS + LD C,A + LD B,0 + ADD HL,BC + LD A,(HL) + OUT (&H98),A + + + Dat gaat een stuk makkelijker omdat die al op de goede + plaats staat. Verder is het analoog. + + + POP BC + INC DE + DEC BC + LD A,B + OR C + JP NZ,CONVRT + + + Hier wordt de lus afgesloten, zodat het hele plaatje wordt + geconverteerd. Door de hier gekozen methode gaat dat + razendsnel! Probeer het maar eens, het programma staat + immers niet voor niets op de diskette. + + Het programma is zo snel omdat de SCREEN 5 data eerst in ��n + keer naar het RAM wordt gekopieerd, waardoor de VDP maar ��n + keer hoeft te worden ingesteld om VRAM te lezen, en daarna + slechts Port #0 (&H98) hoeft te worden gelezen. De SCREEN 8 + data wordt ook in ��n keer naar het VRAM geschreven, + waardoor de VDP ook maar ��n keer voor schrijven hoeft te + worden ingesteld. De routine zou veel en veel langzamer zijn + indien er steeds ��n SCREEN 5 byte zou worden gelezen, dan + weer twee SCREEN 8 bytes schrijven, etc. Dan moeten de SETRD + en SETWRT routines namelijk elke keer weer worden + aangeroepen. + + Tot slot moeten we nog even de slot- en mapperschakeling in + de oude toestand herstellen, en een aantal geheugenplaatsen + defini�ren met DB en DS instructies. Op adres &HFCC1 staat + de slot-ID byte voor het MAIN ROM, voor zowel page 0 als + page 1. + + + ; zet geheugen weer terug in oude stand + + LD A,(OLDMAP) + OUT (&HFE),A ; herstel mapper + LD A,(&HFCC1) + LD H,&H40 + CALL &H24 ; BASIC ROM weer op &H4000 + RET + + OLDMAP: DB 1 + COLORS: DS 16 + PALET: DS 32 + + + Tot slot nog de standaardroutines om de VDP klaar te zetten + voor VRAM lezen resp. schrijven. Er staat genoeg commentaar + in de source, voor verdere uitleg verwijs ik u naar het + begin van de cursus. + + + ; SETWRT + ; Zet VDP klaar om naar VRAM te schrijven + ; In: HL: bit 0-15 van adres + ; C : bit 16 van adres + + SETWRT: LD A,H + RES 7,A + SET 6,A ; 0 1 is VRAM schrijven + JP RDWRT + + ; SETRD + ; Zet VDP klaar om uit VRAM te lezen + ; In: HL: bit 0-15 van adres + ; C: bit 16 van adres + + SETRD: LD A,H + AND &B00111111 ; 0 0 is VRAM lezen + + ; Dit gedeelte is voor beide routines hetzelfde + + RDWRT: PUSH AF ; deze byte moet pas als + ; laatste naar Port #1 + LD A,C ; bit 16 van adres + AND 1 ; alleen bit 0 + LD C,A + LD A,H + AND &HC0 ; alleen bit 6 en 7 + ; (bit 14 en 15 van adres) + OR C ; bit 16 van adres erbij + RLCA + RLCA ; schuif bit 0, 6 en 7 naar + ; bit 0, 1 en 2 + DI + OUT (&H99),A + LD A,14+128 + OUT (&H99),A ; schrijf bit 14-16 van adres + ; naar R#14 + LD A,L ; bit 0-7 van adres + OUT (&H99),A ; naar Port #1 + POP AF ; bit 8-13 van adres, plus VDP + ; instructie + OUT (&H99),A ; naar Port #1 + EI + RET + + + G E B R U I K + + Tot slot nog een aantal wenken voor het geval u de converter + wilt gaan gebruiken. Omdat de converter het palet nodig + heeft, moeten de plaatjes met palet zijn weggeschreven, op + de manier zoals eerder in deze tekst vermeld. Indien u + andere files wilt gebruiken (bijvoorbeeld .SR5 en .PL5 van + GraphSaurus), kunt u daarvoor het BASIC programma zelf + aanpassen. + + Het hele programma draait onder SCREEN 8. Als het SCREEN 5 + plaatje wordt ingeladen ziet dit er dus niet uit. Maakt u + zich daarover niet druk, dat hoort dus zo. U zult zien dat + resultaat qua kleur ietsje afwijkt van het origineel, dat + komt zoals eerder gezegd doordat het blauw in SCREEN 8 + minder nauwkeurig kan worden opgegeven. Hierdoor wordt het + plaatje ook iets donkerder. Hier is verder niets aan te + doen. + + Het zal in de praktijk wel eens voorkomen dat u een SCREEN 5 + plaatje naar SCREEN 8 wilt omzetten, bijvoorbeeld als u een + SCREEN 5 plaatje in Dynamic Publisher wilt inladen. DP kan + namelijk alleen SCREEN 8 plaatjes converteren. + + Ook deze keer wens ik u weer veel succes met het toepassen + van het geleerde. Tot de volgende keer! + + Stefan Boer diff --git a/sunrise_special/7/VDP Cursus 14.md b/sunrise_special/7/VDP Cursus 14.md new file mode 100644 index 0000000..18913d9 --- /dev/null +++ b/sunrise_special/7/VDP Cursus 14.md @@ -0,0 +1,174 @@ + M S X 2 / 2 + V D P C U R S U S ( 1 4 ) + + + + L I N E + + In BASIC is een lijn trekken erg simpel en behoort het LINE + commando tot de eerste commando's die iedereen kent. In ML + is dat wel anders, want het LINE commando is verreweg het + ingewikkeldste commando van de VDP. + + De theorie is reeds in deel 4 van de VDP cursus behandeld, + maar omdat het toch nog vrij ingewikkeld is om aan de hand + daarvan een eigen lijn routine te schrijven, behandel ik + deze keer een standaardroutine om lijnen te trekken. + + De routine is wel enigszins beperkt, aangezien de co�rdi- + naten maar 8 bits zijn. Hierdoor is de routine minder + geschikt voor SCREEN 6 en 7 en de lijnen kunnen maar in 1 + page worden getrokken. + + Laat ik maar meteen beginnen met de source. + + ; L I N E . A S M + ; Trek een lijn (H,L)-(D,E) + ; Kleur=B; Log. op=A + ; Door Stefan Boer + ; VDP Cursus deel 15 + ; Sunrise Magazine #9 + ; (c) Stichting Sunrise 1993 + + LINE: AND &H0F ; logische operatie + OR &H70 ; line + LD (LINDAT+10),A + LD A,B ; kleur + LD (LINDAT+8),A + LD A,H ; DX + LD (LINDAT),A + LD A,L ; DY + LD (LINDAT+2),A + + Het makkelijkst zijn de kleur, logische operatie en begin- + co�rdinaten. Die kunnen zonder verdere problemen alvast + worden ingevuld. &H70 is de opcode voor line. LINDAT is een + blokje met de 11 bytes die zodadelijk naar de VDP worden + gestuurd (registers 36 t/m 46). + + Nu komen de problemen. Het LINE commando van de VDP werkt + namelijk niet zoals alle andere commando's met NX en NY, + maar met Maj en Min. De lijn wordt gezien als de schuine + zijde van een rechthoekige driehoek, waarbij Maj en Min dan + de twee rechte zijden zijn. Maj is de langste en Min de + kortste. + + Met MAJ (bit 0 van het argument register) moet worden + aangegeven of de langste zijde in de x richting is (0) of in + de y richting (1). Verder moet met DIX en DIY zoals + gewoonlijk worden aangegeven of de lijn vanaf (DX,DY) naar + links/rechts resp. boven/beneden gaat. Je snapt wel dat het + even wat logisch nadenken kost om dit alles te programmeren. + + We gaan nu eerst gewoon de NX berekenen, alsof er niks aan + de hand is. NX moet gelijk zijn aan ABS(x1-x2). + + LD A,H ; x1 + SUB D ; x1-x2 + LD D,&B00000100 ; DIX=links + JR NC,LINE_1 ; x1>x2 + LD D,0 ; DIX=rechts + NEG ; positief maken + LINE_1: LD H,A ; NX + + Behalve NX hebben we nu ook meteen DIX, en wel in bit 2 van + D. NY gaat analoog: + + LD A,L ; y1 + SUB E ; y1-y2 + LD E,&B00001000 ; DIY=omhoog + JR NC,LINE_2 ; y1>y2 + LD E,0 ; DIY=omlaag + NEG ; positief maken + LINE_2: LD L,A ; NY + + Ook hier meteen weer DIY, nu in bit 3 van E. Nu gaan we NX + en NY vergelijken om te kijken welke Min en welke Maj (nee, + dat heeft niets te maken met verkeer en waterstaat) wordt. + NY staat nog steeds in A. + + CP H ; vergelijk NX met NY + LD A,0 ; MAJ=X (XOR A kan niet!) + JR C,LINE_3 ; NX>NY + LD C,L + LD L,H + LD H,C ; verwissel NX en NY + LD A,&B00000001 ; MAJ=Y + + Het wisselen van L en H gebeurt via het C register, omdat er + geen EX L,H instructie bestaat. Normaal gesproken gebruik je + natuurlijk altijd XOR A in plaats van LD A,0, maar hier kan + dat niet omdat dan de uitslag van de CP H wordt gewist. De + XOR A voor de CP H zetten kan ook niet, want we hebben de + waarde van A dan nog nodig voor de vergelijking! A bevat nu + MAJ in bit 0, H bevat Maj en L bevat Min. + + (Nvdr. Het "verlies" van XOR A kan wel goed worden gemaakt + met INC A in plaats van LD A,1.) + + + LINE_3: OR D + OR E + LD (LINDAT+9),A ; Arg + LD A,H + LD (LINDAT+4),A ; Maj + LD A,L + LD (LINDAT+6),A ; Min + + In A zat al MAJ, en daar worden DIX en DIY nu bij geORd. + Samen is dat de juiste waarde voor het argument register. + Tot slot worden Maj en Min nog in LINDAT gezet. We hoeven nu + alleen nog de 11 bytes in LINDAT naar de VDP commando + registers 36 t/m 46 te schrijven, waarbij we natuurlijk + eerst moeten checken of de VDP niet nog bezig is met een + ander commando. + + LD BC,&H0B9B + LD HL,LINDAT + CALL VDPRDY + DI + LD A,36 + OUT (&H99),A + LD A,17+128 + OUT (&H99),A + EI + OTIR + RET + + VDPRDY: LD A,2 + CALL RDSTAT + BIT 0,A + JP NZ,VDPRDY + RET + + RDSTAT: DI + OUT (&H99),A + LD A,15+128 + OUT (&H99),A + NOP + NOP + IN A,(&H99) + EX AF,AF + XOR A + OUT (&H99),A + LD A,128+15 + OUT (&H99),A + EI + EX AF,AF + RET + + LINDAT: DB 0,0,0,0,0,0,0,0,0,0,0 + + N.B. De routine zet de lijn nu automatisch in page 0. Wilt u + een andere page, zet die dan op (LINDAT+3). + + + T E N S L O T T E + + De source staat op disk onder de naam LINE.ASC. Het is + natuurlijk ook mogelijk om een 16 bits routine te schrijven, + maar dat is nog een stuk moeilijker dan deze 8 bits routine. + Een korte aflevering dit keer, maar naar ik hoop wel weer + een interessante. De volgende keer ga ik een aantal routines + voor sprites behandelen. Tot dan! + + Stefan Boer diff --git a/sunrise_special/7/VDP Cursus 15.md b/sunrise_special/7/VDP Cursus 15.md new file mode 100644 index 0000000..8c119ff --- /dev/null +++ b/sunrise_special/7/VDP Cursus 15.md @@ -0,0 +1,405 @@ + M S X 2 / 2 + V D P C U R S U S ( 1 5 ) + + + Sunrise Magazine mag dan wel het tweede lustrum vieren, ik + vier met de VDP cursus alweer het derde! Ik had beloofd het + deze keer over sprites te gaan hebben, maar stel dat uit tot + deel 16. + + In plaats daarvan bespreek ik deze keer een routine om + SCREEN 2 naar SCREEN 5 om te zetten, dit naar aanleiding van + een brief van Bert Hoogerdijk uit IJsselstein (zie SRM#9). + Hij gebruikte een zeer langzaam programma (40 minuten per + plaatje!) uit het Belgenblad, en vroeg zich af of het niet + sneller kon. Nou, dat kan! Heeft u ook eens zo'n vraag, + schrijf dan gerust, ik geef graag antwoord! + + + S C R E E N 2 + + Het is alweer een tijdje geleden dat we de opslag van de + schermen in het VRAM hebben behandeld, dus als u het niet + meer weet: zoek het even op in een oud deel van de VDP + cursus. + + Omdat SCREEN 2 vrij ingewikkeld in elkaar zit, leg ik het + hier nog maar eens uit. De beeldinformatie staat bij SCREEN + 2 in drie tabellen: + + patroon generator tabel &H0000-&H17FF (6144 bytes) + patroon naam tabel &H1800-&H1AFF (768 bytes) + kleurtabel &H2000-&H37FF (6144 bytes) + + SCREEN 2 is opgebouwd uit 24 rijen van elk 32 posities, + samen 768 positie. In de naamtabel staat voor elke positie + welk karakter er staat. De vorm en kleur van de karakters + staan in de patroontabel en kleurtabel. + + Om ervoor te zorgen dat er 768 verschillende karakters op + het scherm kunnen staan, is het scherm in drie gedeeltes + verdeeld: + + boven : rij 0 t/m 7 + midden: rij 8 t/m 15 + onder : rij 16 t/m 23 + + Per gedeelte is er een apart gedeelte van de patroon- en + kleurtabel. Een karakter bestaat uit 8x8 pixels. De vorm van + het karakter staat in 8 bytes in de patroontabel en de kleur + in 8 bytes in de vormtabel. In de patroontabel staat een 1 + voor voorgrondkleur en een 0 voor achtergrondkleur, in de + kleurtabel geven de 4 hoge bits de voorgrondkleur aan en de + 4 lage bits de achtergrondkleur. + + + L M M C + + Om de 8x8 karakters op SCREEN 5 te zetten gebruik ik het VDP + commando LMMC, wat staat voor Logical Move CPU to VRAM. U + kunt de werking van dit commando uitgebreid nalezen in een + oud deel van de VDP cursus, maar in het kort komt het hierop + neer: + + - Geef met DX, DY, NX en NY een rechthoek in het VRAM aan + - Stuur de pixels een voor een naar R#44 + + Een klein addertje onder het gras is dat we bij de aanroep + van de routine het eerste pixel al mee moeten geven! Dit + maakt een klein omweggetje in onze routine noodzakelijk. + + Om het palet hoeven we ons geen zorgen te maken, omdat in + SCREEN 2 toch alleen het standaardpalet wordt gebruikt. + + Hoog tijd voor de ML source, die deze keer netjes top down + is geprogrammeerd. Zoals gewoonlijk staat hij in ASCII + formaat op de disk onder de naam SC2SC5.ASC (in de file + SC2SC5.PMA). + + + ; S C 2 S C 5 . A S M + ; Zet SCREEN 2 plaatje om naar SCREEN 5 + ; Door Stefan Boer + ; Sunrise Magazine #10 + ; (c) Stichting Sunrise 1993 + + ; SCREEN 2 plaatje moet bij aanroep in RAM staan + ; op &H9000-&HCFFF, SCREEN 5 moet actief zijn + + + SC2DAT: EQU &H9000 ; adres van SC2 data in RAM + + + ORG &HD000 + + Voor de snelheid laden we het SCREEN 2 plaatje (in feite + gewoon het complete MSX1 VRAM van 16 kB) in het RAM vanaf + adres &H9000, dit kan gewoon met BLOAD"NAAM",&H9000. Het + plaatje staat dan van &H9000 t/m &HCFFF, zodat we de routine + op &HD000 laten beginnen. + + + ; initialisatie + + DI + XOR A + LD (REGEL),A + LD HL,SC2DAT+&H1800 + LD (NAAMAD),HL ; pointer naamtabel + LD IX,FLAG + + + ; hoofdprogramma + + REGLUS: CALL DOREGL ; zet een regel om + LD A,(REGEL) + INC A + CP 24 ; klaar? + JR Z,EINDE + LD (REGEL),A + JR REGLUS ; volgende regel + EINDE: EI + RET + + + Het hoofdprogramma roept voor elke regel een routine aan die + de regel omzet naar SCREEN 5. + + + ; zet een regel om + + DOREGL: XOR A + LD (KOLOM),A ; initialisatie + KARLUS: CALL DOKAR ; zet een karakter om + LD A,(KOLOM) + INC A + CP 32 ; klaar? + RET Z + LD (KOLOM),A + JR KARLUS + + + Ook hier gebeurt nog niets moeilijks, hier wordt voor elk + karakter een routine aangeroepen die dat karakter omzet naar + SCREEN 5. Zoals u ziet wordt precies de volgorde van de + naamtabel aangehouden, dat scheelt rekenwerk. + + + ; zet een karakter om + + DOKAR: LD HL,(NAAMAD) ; adres naamtabel + LD A,(HL) ; nummer uit naamtabel lezen + INC HL + LD (NAAMAD),HL + PUSH AF + CALL GETCAD ; bereken adres in kleurtabel + LD (KLR_AD),HL + POP AF + CALL GETGAD ; bereken adres generator tab + LD (GEN_AD),HL + RES 0,(IX+0) ; 1ste pixel nog niet gedaan + LD B,8 + PIXLUS: CALL DO8PIX ; zet regeltje van 8 pixels om + DJNZ PIXLUS + RET + + + Eerst wordt het nummer van het huidige karakter uit de + naamtabel gehaald. Zoals ik het nu geprogrammeerd heb bevat + (NAAMAD) steeds het adres dat hoort bij KOLOM en REGEL, + waardoor er niet extra gerekend hoef te worden. Bij het + karakternummer worden de bijbehorende adressen in de + patroon- en kleurtabel uitgerekend. + + IX+0 wijst naar een adres waar we met bit 0 bijhouden of het + huidige pixel het eerste pixel is van het huidige 8x8 + blokje. Dit is nodig omdat bij het naar de VDP sturen van + het LMMC commando het eerste pixel al bekend moet zijn. + + Een karakter bestaat uit 8 regels van 8 pixels, in de lus + PIXLUS worden deze 8 regels ��n voor ��n omgezet. + + + ; Bereken adres in kleurtabel + ; In : A=karakternummer + ; Uit: HL=adres + + GETCAD: LD L,A + LD H,0 + ADD HL,HL + ADD HL,HL + ADD HL,HL ; *8 + LD DE,SC2DAT+&H2000 + ADD HL,DE + LD A,(REGEL) + CP 8 + RET C ; bovenste gedeelte + LD DE,&H0800 + ADD HL,DE + CP 16 + RET C ; middelste gedeelte + ADD HL,DE ; onderste gedeelte + RET + + + Eerst wordt 8*A uitgerekend en in HL gezet. Vervolgens wordt + het beginadres van de kleurtabel (die in dit geval in het + RAM staat vanaf adres &H9000!) uitgerekend. Tot slot wordt + gekeken in welk gedeelte van het scherm we ons bevinden, en + wordt er indien nodig ��n (middelste gedeelte) of twee maal + (onderste gedeelte) &H800 bij het adres opgeteld. + + + ; Bereken adres in patroon generator tabel + ; In: A=karakternummer + ; Uit: HL=adres + + GETGAD: LD L,A + LD H,0 + ADD HL,HL + ADD HL,HL + ADD HL,HL ; *8 + LD DE,SC2DAT + ADD HL,DE + LD A,(REGEL) + CP 8 + RET C ; onderste gedeelte + LD DE,&H0800 + ADD HL,DE + CP 16 + RET C ; middelste gedeelte + ADD HL,DE ; onderste gedeelte + RET + + + Deze routine is bijna gelijk aan de vorige, het enige + verschil is dat het beginadres van de patroontabel &H0000 is + in plaats van &H2000. + + + ; Zet een rijtje van 8 pixels om + + DO8PIX: CALL GETCOL ; lees kleuren + CALL GETBYT ; lees een byte v/h karakter + PUSH BC + LD B,8 + DOPIX: LD A,D ; voorgrondkleur + RL C + JR C,DOPIX2 + LD A,E ; bit 0, dus achtergrond kleur + DOPIX2: BIT 0,(IX+0) ; flag eerste pixel + JR Z,FSTPIX + OUT (&H9B),A ; pixel naar VDP + DJNZ DOPIX + POP BC + RET + FSTPIX: CALL SETVDP ; 1ste pixel, commando n. VDP + DEC B + JR DOPIX + + + Dit gedeelte doet het eigenlijke omzetwerk. Eerst worden de + gegevens van het huidige rijtje van 8 pixels uit de kleur- + en patroontabel gelezen (GETCOL en GETBYT). De kleuren staan + nu in D en E en de 'vorm' in C. Vervolgens schuiven we de + bits van C ��n voor ��n in de carry, omdat we dan makkelijk + kunnen testen. Is het bit 1 dan sturen we de voorgrondkleur + naar de VDP en is het bit 0 dan sturen we de + achtergrondkleur naar de VDP. + + Voor het schrijven naar R#44 gebruiken we indirecte + adressering zonder auto increment, wat erop neer komt dat we + de kleuren gewoon achter elkaar naar poort #3 (I/O adres + &H9B) kunnen sturen, zoals hier ook gebeurt. + + Ik heb het al eerder gehad over het addertje onder het gras + met LMMC, we moeten bij het geven van het commando de kleur + van het eerste pixel al meegeven. Daarvoor dient de + instructie met bit 0 van (IX+0). Bij het eerste pixel wordt + de routine SETVDP aangeroepen in plaats van dat het gewoon + naar &H9B wordt geschreven. + + + ; Lees kleuren + ; Uit: E=achtergrondkleur, D=voorgrondkleur + + GETCOL: LD HL,(KLR_AD) + LD A,(HL) + INC HL + LD (KLR_AD),HL + PUSH AF + AND &H0F + LD E,A ; achtergrondkleur + POP AF + AND &HF0 + RRCA + RRCA + RRCA + RRCA + LD D,A ; voorgrondkleur + RET + + + Deze routine leest een byte uit de kleurtabel en zet de + voorgrond- en achtergrondkleur in respectievelijk D en E. + + + ; Lees een byte van het karakter + ; Uit: C=byte + + GETBYT: LD HL,(GEN_AD) + LD C,(HL) + INC HL + LD (GEN_AD),HL + RET + + + Deze routine leest een byte uit de patroontabel, dit is een + stuk simpeler omdat er verder niets meer hoeft te worden + gerekend. + + De nu volgende routine wordt steeds voor elk 8x8 blokje + aangeroepen zodra de kleur van het eerste pixel bekend is. + De VDP wordt klaargezet om een blokje van 8x8 pixel voor + pixel te vullen, waarbij de data naar &H9B moet worden + geschreven. + + + ; Zet VDP klaar om SCREEN 5 data te ontvangen + ; In: A=kleur van eerste pixel + + SETVDP: EX AF,AF + LD A,36 + OUT (&H99),A + LD A,17+128 + OUT (&H99),A ; 36 --> R#17 + + LD A,(KOLOM) + RLCA + RLCA + RLCA ; *8 + OUT (&H9B),A ; DX + XOR A + OUT (&H9B),A + LD A,(REGEL) + RLCA + RLCA + RLCA ; *8 + OUT (&H9B),A ; DY + XOR A + OUT (&H9B),A + + LD A,8 + OUT (&H9B),A ; NX + XOR A + OUT (&H9B),A + LD A,8 + OUT (&H9B),A ; NY + XOR A + OUT (&H9B),A + + EX AF,AF + OUT (&H9B),A ; kleur eerste pixel + XOR A + OUT (&H9B),A ; ARG + LD A,&HB0 ; LMMC + OUT (&H9B),A ; commando + + LD A,44+128 ; zonder auto increment naar + OUT (&H99),A ; R#44 schrijven + LD A,17+128 + OUT (&H99),A ; 44+128 --> R#17 + + SET 0,(IX+0) ; flag eerste pixel gedaan + RET + + + Het valt je misschien op dat ik helemaal niet controleer of + de VDP wel klaar is met het vorige commando. Dat is hier + niet nodig, want de VDP is zo snel dat zelfs de R800 het + niet kan bijhouden met het rekenwerk. Het checken op het + Command Execute bit heeft dus geen zin en zou de routine + alleen onnodig vertragen. + + + ; variabelen + + REGEL: DB 0 ; huidige regel + KOLOM: DB 0 ; huidige kolom + FLAG: DB 0 ; flag eerste pixel gedaan + NAAMAD: DW 0 ; huidig adres in naamtabel + KLR_AD: DW 0 ; huidig adres in kleurtabel + GEN_AD: DW 0 ; in pattern generator tabel + + + Tot slot wordt ruimte geserveerd voor de opslag van de + benodigde variabelen. + + + T E N S L O T T E + + In SC2SC5.PMA zitten verder nog SC2SC5.BIN, SC2SC5.BAS en + NEMESIS.VRM, waarmee u de routine even kunt uitproberen (de + .BAS file RUNnen). U zult zien dat het zeer snel gaat! + + Tot de volgende keer, + Stefan Boer diff --git a/sunrise_special/7/VDP Cursus 16.md b/sunrise_special/7/VDP Cursus 16.md new file mode 100644 index 0000000..449892a --- /dev/null +++ b/sunrise_special/7/VDP Cursus 16.md @@ -0,0 +1,251 @@ + + M S X 2 / 2 + V D P C U R S U S ( 1 6 ) + + + Ik zal de spritefans ook deze keer weer teleurstellen, want + ik kreeg naar aanleiding van mijn oproep om met vragen te + komen een vraag van een lezer hoe je het 'Xak effect' in ML + maakt. De spritefans hoeven zich niet gelijk voor de trein + te gooien, want op Sunrise Special #5 geeft R�man v/d + Meulen, een van de programmeurs van Fuzzy Logic, zijn + geheimen op spritegebied prijs. + + + X A K E F F E C T + + Er zijn misschien lezers die nu met opgetrokken wenkbrauwen + voor de monitor zitten. Xak effect? Wat is dat? In de demo + van Xak The Tower of Gazzel zit een heel mooi effect, het + lijkt erop alsof het woord Xak op het scherm wordt + 'gegoten'. Als u het nog nooit gezien heeft, bekijk dan maar + het voorbeeld van de routine die ik deze keer ga bespreken + door XAK.BAS te RUNnen. Alle files behorende bij dit artikel + zitten in XAKEFFCT.PMA. + + Hoe werkt het nu precies? Stel het plaatje moet uiteindelijk + vanaf lijn 100 op het scherm komen te staan. Dan kopieer je + eerst de eerste lijn van het plaatje naar lijn 211 t/m 100, + daarna de tweede lijn naar lijn 211 t/m 101, etc. + + Voor het voorbeeld gebruiken we het logo van Overflow!, zie + de rubriek Backgrounds voor meer informatie over deze groep. + Dit logo is 102 lijnen hoog. Om te zorgen dat het restje aan + het eind wordt uitgewist, nemen we een extra zwarte lijn + onderaan het plaatje mee, waardoor het totaal op 103 komt. + We zetten het plaatje bovenaan op page 1, en we willen dat + het midden op page 0 terecht komt. + + Als je het Xak effect nu zonder verder nadenken in BASIC zou + programmeren voor dit logo, krijg je ongeveer zoiets: + + FOR I=0 TO 102 + FOR Y=211 TO 55+I STEP -1 + COPY (0,I)-(255,I),1 TO (0,Y) + NEXT + NEXT + + De I-lus gaat het plaatje lijn voor lijn af, de Y lus + kopieert die lijn van onderaf tot aan de juiste positie. Als + je FOR Y=55+I TO 211 zou doen, dan zou je het er heel stom + uitzien, omdat het kopi�ren dan tegen de 'gietrichting' in + gaat. + + Dit gaat in BASIC niet vloeiend, en ook in ML niet echt. Het + kan veel handiger door de VDP het vuile werk op te laten + knappen. Het kan met slechts twee copy's per lijn!!! + + + S L I M W I S S E N + + Het lijkt of ik nu naar een heel onderwerp ga, maar dat is + toch niet zo. Als je in ML een gebied vanaf Begin met lengte + Lengte met de waarde Waarde wilt vullen, dan doe je dat zo: + + LD HL,Begin + LD DE,Begin+1 + LD BC,Lengte-1 + LD (HL),Waarde + LDIR + + Dit gaat zo. Je zet zelf de waarde al op het begin. De Z80 + (of R800) leest (Begin) en zet die waarde op (Begin+1). + Daarna leest hij (Begin+1) en zet die waarde op (Begin+2), + etc. Zo wordt dus het hele gebied met de juiste waarde + gevuld! + + + E N N U I N M L + + Dit truukje gebruiken we ook bij het Xak effect. We kopi�ren + de lijn maar ��n keer, en wel naar (0,211). Daarna kopi�ren + we een blok van de juiste hoogte van (0,211) naar (0,210) + [een blok dat naar boven is gericht]. De VDP kopieert eerst + lijn 211 op lijn 210, daarna lijn 210 op 209, etc. Precies + wat we willen hebben! + + In ML ziet dit er als volgt uit: + + + ; Xak effect + ; XAK.GEN + ; Door Stefan Boer + ; VDP Cursus Sunrise Magazine #11 + ; (c) Stichting Sunrise 1994 + ; v1.0 20/01/94 + + Bron_X: EQU 0 + Bron_Y: EQU 0 + Bron_Page: EQU 1 + Doel_X: EQU 0 + Doel_Y: EQU 55 + Doel_Page: EQU 0 + Breedte: EQU 256 + Hoogte: EQU 103 + + + Om ervoor te zorgen dat de routine universeel bruikbaar is + gebruik ik voor alle gegevens betreffende het plaatje EQU's. + X-co�rdinaten en Breedte worden als words behandeld, zodat + de routine ook voor SCREEN 7 en voor plaatjes van 256 breed + (SCREEN 5 over de hele breedte) geschikt is. + + + DB #FE + DW Start + DW Einde + DW Start + + + Dit is de .BIN header voor GEN80, die WB-ASS2 gebruikers + kunnen overslaan. + + + ORG #D000 + + Start: LD HL,Copy_Lijn + CALL DoCopy + + LD HL,Copy_Effect + CALL DoCopy + + LD A,(Copy_Effect+10) ; Hoogte + DEC A + LD (Copy_Effect+10),A + + LD A,(Copy_Lijn+2) ; Bron_Y + INC A + LD (Copy_Lijn+2),A + + CP Bron_Y+Hoogte ; klaar? + JR NZ,Start + + RET + + + Ja, dit is het hele hoofdprogramma. Gewoon twee copy's. Bij + Copy_Lijn wordt steeds de lijn verhoogd die wordt + gekopieerd, en bij Copy_Effect wordt steeds de hoogte van + het blok met ��n verkleind. + + + Copy_Lijn: DW Bron_X + DB Bron_Y,Bron_Page + DW Doel_X + DB 211,Doel_Page + DW Breedte,1 + DB 0,0,#D0 + + Copy_Effect: DW Doel_X + DB 211,Doel_Page + DW Doel_X + DB 210,Doel_Page + DW Breedte,210-Doel_Y + DB 0,8,#D0 ; DIY = 1 + + + Dit zijn de data's voor de copy's, waarbij zoals ik al had + gezegd alles wat met X te maken heeft met DW's is gedaan + zodat de routine universeel bruikbaar is. Ik gebruik hier de + High Speed copy (#D0), dus let erop dat de x-co�rdinaat even + moet zijn in SCREEN 5. DIY = 1 bij de tweede copy, zodat er + van onder naar boven wordt gekopieerd. + + Nu volgen nog de standaardroutines DoCopy, ReadStatus en + VDPReady, die inmiddels bekend worden verondersteld. + + + ; ---------------------------------------------------------- + ; DoCopy + ; Voer VDP commando uit + ; In : HL = startadres 15 bytes + ; Gebruikt: AF, HL, BC + ; ---------------------------------------------------------- + + DoCopy: CALL VDPReady + DI + LD A,32 + OUT (#99),A + LD A,17+128 + OUT (#99),A + EI + LD BC,#0F9B + OTIR + RET + + + ; ---------------------------------------------------------- + ; VDPReady + ; Wacht tot VDP klaar is met commando executie + ; Gebruikt: AF + ; ---------------------------------------------------------- + + VDPReady: LD A,2 + CALL ReadStatus + BIT 0,A + JR NZ,VDPReady + RET + + + ; ---------------------------------------------------------- + ; ReadStatus + ; Lees VDP statusregister + ; In : A = nummer van te lezen statusregister + ; Uit : A = data + ; Gebruikt: AF' + ; ---------------------------------------------------------- + + ReadStatus: DI + OUT (#99),A + LD A,15+128 + OUT (#99),A + NOP + NOP + IN A,(#99) + EX AF,AF' + XOR A + OUT (#99),A + LD A,128+15 + OUT (#99),A + EI + EX AF,AF' + RET + + Einde: END + + + T E N S L O T T E + + Op de disk staan XAK.GEN, XAK.BAS, XAK.BIN en OVERFLOW.SC5 + (in de file XAKEFFCT.PMA). U kunt de routine uitproberen + door XAK.BAS te RUNnen, het Overflow! logo wordt dan op het + scherm 'gegoten'. + + Als er nog meer lezers zijn die iets te vragen op VDP + gebied, schrijf het me dan! Anders is dit het laatste deel + van de VDP cursus. + + Stefan Boer + + P.S. Ik begin binnenkort met een V9990 cursus, daarop kan + dit effect natuurlijk ook worden gemaakt, alleen dan + nog spectaculairder! diff --git a/sunrise_special/7/Valburg reactie.md b/sunrise_special/7/Valburg reactie.md new file mode 100644 index 0000000..15f6e1d --- /dev/null +++ b/sunrise_special/7/Valburg reactie.md @@ -0,0 +1,257 @@ + V A L B U R G R E A K T I E + + + Ik ben geroerd. Tegen mijn verwachting in heeft iemand (Jan + van Valburg) de moeite genomen om eens te reageren op ��n + van mijn literaire brouwsels (Sunrise Special #6). Dankjewel + Jan, het komt namelijk zelden tot nooit voor dat er reakties + komen op artikelen die door het gilde van Sunrise + medewerkers geschreven worden, wat wij overigens zeer jammer + vinden. Het lijkt wel alsof alle abonnementen van de Special + op kerkhoven worden bezorgd wat de stilte van de kant van de + lezers zou verklaren. + + Daar komt nog bij dat het artikel van Jan de 'totaal andere + aanpak' een uitermate frisse kijk geeft op een manier van + programmeren die zijn vruchten sinds het CP/M tijdperk heeft + afgeworpen. Jan omschrijft in zijn artikel het bijhouden van + een standaard kernel als leuk en interessant, maar weinig + nuttig en dat kan ik natuurlijk niet zomaar over mijn kant + laten gaan. Dergelijke uitspraken schreeuwen om een + weerwoord, maar daarover later meer. + + + D E B E S T E O N T W I K K E L O M G E V I N G + + Laat ik beginnen met het introduceren van twee termen die + nogal eens zullen vallen in de rest van dit artikel. Een + programmeeromgeving definieer ik als de feitelijke assembler + of compiler, met eventueel in combinatie een linker en + librarian (een programma dat libraries onderhoud). Met een + ontwikkelomgeving bedoel ik alle andere software die + daarnaast nog nodig is, zoals een editor, een debugger, een + RAMdisk en (heel belangrijk) het Operating System. + + Iemand die een softwareprojekt aan het uitwerken is waarbij + een aanzienlijke hoeveelheid code en data komt kijken heeft + behoefte aan een goede ontwikkelomgeving. Deze omgeving moet + ondersteunend werken wat zoveel betekent als het voorkomen + van ergernissen die in principe niets met het projekt te + maken hebben. Denk hierbij aan resource (geheugen, + diskruimte etc.) conflicten tussen de compiler en het + project. Ook het omschakelen tussen programmeeromgeving en + het programma zelf moet vlekkeloos en snel gaan. + + DOS kan als ontwikkelomgeving gebruikt worden. Het hele + concept van DOS draait om een 'single user / single process' + omgeving. Op ��n moment kan er dus maar 1 programma draaien, + door ��n gebruiker. Dat betekent dus dat bv. een assembler + en linker niet tegelijkertijd aktief kunnen zijn tenzij ze + onderdeel zijn van hetzelfde programma. Indien je geen + Harddisk hebt is dit een hel, omdat de ontwikkelomgeving + plotseling tegen je werkt door fikse tijdsvertragingen te + introduceren. + + Jan noemt in zijn artikel een bij hem ontwikkelde aversie + tegen WB-ASS2 en ik begrijp dat best. GEN80 in combinatie + met een Linker en Librarian is inderdaad heel, heel veel + beter. Indien je daarnaast echter niet de beschikking hebt + over een turbo R met Harddisk worden deze voordelen teniet + gedaan door de enorme traagheid van de omgeving. Jan noemt + dit niet met zoveel woorden, maar ik kan uit zijn artikel + opmaken dat hij er net zo over denkt (denk ik). Een RAMdisk + biedt daarbij niet zoveel soelaas omdat je dan nl. erg + voorzichtig moet zijn met welk geheugen je gebruikt. + + Aangenomen dat je in het bezit bent van een super MSX- + configuratie, dan nog stuit ik op ��n aanzienlijk nadeel van + de GEN80 / DOS omgeving. De assembler, de linker en de + librarian (de programmeeromgeving) vormen samen een redelijk + nauw samenwerkend geheel. Ze begrijpen elkaars in- en + uitvoer prima waardoor de gebruiker hier geen enkel probleem + zal tegenkomen. Elk ander onderdeel van de omgeving (editor + en debugger) is echter niet verwant aan de andere + programma's. Dat hoeft op zich geen probleem te zijn en het + zal op MSX nauwelijks voor problemen zorgen, maar het + beperkt de theoretische mogelijkheden toch wat. + + Waarom is de assembler van WB-ASS bv. zo snel? Het antwoord + schuilt in de aanverwante editor. Deze produceert nl. geen + ASCII bestanden, maar een getokeniseerde versie zoals BASIC. + De assembler kan zijn werk veel sneller doen doordat er in + de editor reeds een vorm van 'pre-processing' is gedaan. Het + zijn dit soort 'kleine' dingen die een ontwikkelomgeving tot + ongekende doelmatigheid doen stijgen. WB-ASS2 mag dan zijn + nadelen en beperkingen hebben, maar de combinatie + editor/assembler levert aanzienlijke tijdwinsten tijdens het + assembleren die met GEN80 onmogelijk te halen zijn. + + Ik kan het niet laten om hier ook even bij andere + computersystemen stil te staan. Overal om me heen zie ik + advertenties in bladen die een samensmelting van + programmeer- en ontwikkelomgeving propageren. Een uitstekend + voorbeeld is bv. Borland-C voor de PC. + + Borland-C is een ge�ntegreerde C++ compiler met de editor, + compiler, linker en librarian in ��n programma. + Voordelen: + - De editor is zeer geschikt om programma's mee te schrijven + - De linker in nagenoeg onzichtbaar voor de gebruiker omdat + alles automatisch gaat. + - Dit geldt ook voor de librarian + - De ontwikkelde software werkt voor het oog van de gebrui- + ker vlekkeloos met de omgeving samen. De gebruiker hoeft + bv. niet zelf tussen verschillende programma's heen en + weer te springen. + + Nadelen: + - Het is een drug, want je wilt nooit meer iets hebben dat + minder lekker werkt (alhoewel er wel betere C compilers + zijn). + + Om nog eens aan te tonen wat ik bedoel zal ik nog een + voorbeeld geven van de enorme invloed die een kleine ingreep + kan hebben. In Borland-C kunnen meerdere listings + tegelijkertijd open staan. Deze listings staan in vensters + die je met de muis kunt besturen. Op het moment dat je het + programma verlaat kan je het programma opdracht geven om de + 'desktop' te saven. Alle posities van vensters en inhoud + worden op deze manier bewaard. Start je het programma nu + opnieuw op, dan wordt de situatie van voor het afsluiten + hersteld en kan je meteen verder werken. Natuurlijk zou het + niet veel tijd kosten om al die bestanden weer even met het + handje te openen, maar daar wordt je behoorlijk moe van na + 30 keer. Een uiterst kleine geste van het programma kan dus + een grote invloed op de funktionaliteit van het geheel + hebben. + + + T O D O S O R N O T T O D O S + + Wat is nu het fundamentele verschil tussen de beste DOS + assembler (GEN80) en de beste BASIC assembler (WB-ASS)? Het + antwoord luidt, de bron en bestemming van data. GEN80 moet + en zal een file als input hebben en genereert ook alleen + maar files als uitvoer. WB-ASS is wat dat betreft veel + flexibeler, maar je kunt praktisch stellen dat WB-ASS + geheugen als invoer neemt en geheugen of een file als + uitvoer heeft. + + Wat is nu het fundamentele verschil tussen DOS en BASIC? Het + antwoord luidt hier dat DOS programma's op een vast adres + laadt en de gebruiker bij BASIC alles zelf maar uit moet + zoeken. Dat eist in de eerste plaats een behoorlijke kennis + van de gebruiker (lijkt me niet onredelijk om dat van een + programmeur te vragen), maar cre�ert ook een waanzinnige + flexibiliteit en controlevermogen over de inhoud van het + geheugen. Nadeel is wel dat dit controlevermogen maar zover + reikt als de kennis van de gebruiker over de gebruikte + programma's. + + Stel dat bv. TED of DD-Graph vanuit BASIC opgestart zouden + kunnen worden en je deze programma's in combinatie met + WB-ASS tegelijkertijd in het geheugen wilt hebben om er + zonder te laden mee te kunnen werken. Dat lukt alleen + wanneer je heel precies zou weten welk geheugen de + respektievelijke programma's gebruiken. Conclusie: met het + hudige Operating System van MSX is dit praktisch onmogelijk. + Dat wil niet zeggen dat het een onoplosbaar probleem is, + maar helaas voor MSX is het te laat. Het zou nl. een + allesomvattend geheugenbeheer programma moeten krijgen dat + onlosmakelijk met het Operating System is verbonden. + + Nu komt daar toch heel stiekem de door Jan afgeraden Kernel + om de hoek kijken. De door ons geschreven F-Kernel (want zo + heet het ding) heeft integraal geheugenbeheer en al onze + programma's houden er rekening mee. Dat betekent praktisch + dat geheugen niet zomaar genomen kan worden, maar dat het + netjes aangevraagd moet worden. Dat lijkt omslachtig en + i.v.m. vaste adressen in code ook heel onhandig, maar ik kan + uit ervaring meedelen dat het juist het omgekeerde is. + WB-ASS is daarbij zo verbouwd dat het vlekkeloos met de + F-Kernel samenwerkt. Andere programma's kunnen natuurlijk + niet zomaar opgestart worden (misschien een idee voor de + toekomst), maar dat is niet anders. + + Ondertussen groeit het aantal programma's dat van de + F-Kernel gebruik maakt gestaag. Utilities en uitbreidingen + van het Operating System zelf; allen houden ze zich netjes + aan de afspraken en kunnen zonder problemen in combinatie + met andere F-Kernel programma's in het geheugen aanwezig + zijn. Het heeft natuurlijk veel werk gekost om dit alles te + bereiken, maar het verandert een MSX met een aanzienlijke + hoeveelheid geheugen in een ware tovermachine. Dat neemt + niet weg dat het feest pas compleet is wanneer we ook een + assembler hebben met betere mogelijkheden. + + De F-Kernel is niet een file met een hoop standaard routines + die je net zo goed in een library kunt stoppen, maar een + Operating System met een specifiek doel dat de hele computer + naar zijn hand zet en integratie van projekt en + ontwikkelomgeving mogelijk maakt. + + In dit verband ben ik ook uitermate benieuwd naar de + aangekondigde assembler van Compjoetania (Compass) die de + voordelen van WB-ASS en GEN80 zou moeten gaan combineren. + Indien dit een pakket wordt dat van de specifieke + mogelijkheden van MSX gebruik maakt, met alle mogelijkheden + van GEN80 en L80 waarbij in het geval van DOS2 netjes met + geheugen wordt omgesprongen etc. dan kan het niet anders dat + straks iedere zichzelf respekterende programmeur hiermee zal + werken. [Nvdr. Helaas, linken is (nog?) niet mogelijk met + Compass.] Heerlijk, een file laden door alleen de muis te + besturen via pull-down menu's. Debug faciliteiten waarmee + tussentijdse breakpoints gezet kunnen worden waardoor het + debuggen van kleine routines in een groter geheel doodsimpel + wordt. + + Alweer hoor ik mensen klagen: "Ja maar dat kost veel teveel + geheugen". Onzin, een programma kan niet teveel geheugen + kosten. Het is een historisch feit dat programmeurs altijd + meer geheugen moeten hebben als dat het te schrijven + programma nodig heeft en dus is dit geen bezwaar. De tijd + dat een MSX met 128kB voldoende zou zijn is voorbij. Om echt + lekker uit de voeten te kunnen is 512kB toch zeker nodig. + Dit natuurlijk wel in combinatie met programma's die weten + hoe ze met geheugen om moeten gaan. + + Zou ik mijn geluk kunnen rekken door de heren van + Compjoetania te vragen alvast hun visie op het te ontstane + produkt toe te lichten ? Indien jullie dat doen dunkt me dat + een aanzienlijke hoeveelheid Special lezers (moi incluis) de + volgende keer watertandend het desbetreffende artikel zullen + verslinden, uitprinten en inlijsten. + + + T O T S L O T + + Jan beveelt (wat een dwingend woord eigenlijk) het gebruik + van GEN80 met de alleskunnende linker aan. Ik deel die + mening, maar alleen zolang je een turbo R met Harddisk hebt. + In alle andere gevallen moet je het zelf maar weten. Wij van + Fuzzy Logic hebben gekozen voor een door ons behoorlijk + verbouwde versie van WB-ASS (Shadow voegt tegenwoordig al + eigen commando's aan WB-ASS toe) waarmee we in combinatie + met onze F-Kernel minstens zo lekker werken als anderen met + GEN80. + + Jan (en natuurlijk ook vele anderen) gebruiken een externe + linker waarmee zowel code als data aan elkaar kunnen worden + geknoopt. De F-Kernel is nog niet zo ver en kan alleen maar + data aan elkaar linken, maar we zijn op de goede weg. + + Jan heeft nooit niet gebruikte routines in zijn programma's + en wij wel, maar dat zal de gemiddelde koper van software + een rotzorg zijn. + + Indien het produkt van de heren van Compjoetania echt goed + wordt en een zeer volledig uitgevoerde ontwikkelomgeving + cre�ert, dan schakelen wij ongetwijfeld over. Het zijn nl. + niet de mogelijkheden van de programmeeromgeving die + doorslaggevend zijn voor de keuze van een pakket, maar de + mogelijkheden en handigheid van de ontwikkelomgeving. + Flexibliteit van de laatst genoemde is daarbij van + essentieel belang omdat iedereen zijn eigen inhoud aan de + omgeving moet kunnen geven. + + Alex van der Wal