/* Copyright (c) Günter Woigk 2012 - 2015 mailto:kio@little-bat.de This file is free software This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: • Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. • Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Dual UART 88C192 Driver for K1-Bus Board ---------------------------------------- This is the driver for a dual-sio board for the K1-Bus. For K1-Bus see: http://k1.spdns.de/Develop/Hardware/K1-Bus/ For driver EEprom definition see: http://k1.spdns.de/Develop/Hardware/K1-Bus/i2c-eeprom.pdf UART Port Connections: ---------------------- OP0 RTSA or Inverter Control for CLKA.out (normally asserted (low) -> not inverted) OP1 RTSB or Inverter Control for CLKB.out (normally asserted (low) -> not inverted) OP2 CLKA or Inverter Control for RTSA (should be asserted (low) -> not inverted) OP3 CLKB or Inverter Control for RTSB (should be asserted (low) -> not inverted) OP4 CTLA pin header OP5 CTLB pin header OP6 CLKA.in.INV Inverter Control for CLKA.in und CTSA (normally asserted (low) -> not inverted) OP7 CLKB.in.INV Inverter Control for CLKB.in und CTSB (normally asserted (low) -> not inverted) IP0 CTSA from HSKA IP1 CTSB from HSKB IP2 +5V IP3 TXACLK from HSKA IP4 RXACLK from HSKA IP5 TXBCLK from HSKB IP6 RXBCLK from HSKB */ #include "options.h" /* Copyright (c) Günter Woigk 2009 - 2015 mailto:kio@little-bat.de This file is free software This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: • Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. • Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. Dieses File darf nur #defines enthalten. Es wird von c-Sourcen und vom Assembler eingebunden! */ // Welcher Quartz-Vorteiler soll maximal eingestellt werden? // 2 -> 32/2 = 16 MHz // 4 -> 32/4 = 8 MHz // 8 -> 32/8 = 4 MHz // 16 -> 32/16 = 2 MHz // Der mca Assembler kennt 'clock_predivider' und ersetzt ggf. set clock2 und set clock4. // #define clock_predivider 4 // sollen die Microcode Macros 'log', 'trace' und 'tron' in 'macros.h' aktiviert werden? // Auch: Einbinden der Bytecode-Namen im BytecodeCompiler. // #define enable_debug_macros 1 // Der i2c-Treiber "i2c.cc" kann Code enthalten, der einen Treiber aus einem Array // statt aus dem i2c eeprom liest. Damit kann ein K1-Bus-Treiber erstmalig // ins System eingebracht werden. // // wenn include_i2c_soft_eeprom != 0 wird dieser Code für dieses Device eingebaut, zB. Device 3. // wenn include_i2c_soft_eeprom == 0 wird kein derartiger Code eingebaut. // // Die Daten für den Array werden in "i2c.cc" aus der Datei "i2c-sio-eeprom.h" importiert. // Dieses kann mit dem Script "eeprom.vs" aus der Datei "eeprom.bin" erzeugt werden. // eeprom.bin = output file des VCC Compilers für Target K1-Bus-Bytecode. // eeprom.vs = Script sollte in diesem Ordner ("…/Microcode/mc/eeprom.vs") liegen. // #define include_i2c_soft_eeprom 0 #define i2c_sio_addr 2 // falls include_i2c_soft_eeprom enabled // Der Driver für die Sio-Karte kann in Millicode implementiert sein. // Dann muss dieser Treiber nicht aus dem Eeprom geladen werden // #define include_sio_driver_in_rom 1 // Soll das EEFS Filesystem eingebaut werden? // #define include_filesystem 0 // Sollen die FP-Funktionen eingebaut werden? // #define include_floating_point 0 // sollen test-module eingebaut werden? // globales flag für alle test module. // test-module müssen zusätzlich individuell enabled werden. // #define include_tests 0 #define test_millicode 0 #define test_long 0 #define test_float 0 #define test_misc 0 #define test_i2c 0 // soll der ram-test übersprungen werden? // vor allem sinnvoll in der Emulation wg. Laufzeit. B-) // #define include_ramtest 1 // soll Datentyp bool signed oder unsigned sein? // unsigned: 0, 1 // signed: 0, -1 // unsigned ist C-Standard, signed wäre aber eine Winzigkeit schneller & kürzer // #define signed_bool 0 #include "stdc.h" /* Copyright (c) Günter Woigk 2009 - 2015 mailto:kio@little-bat.de This file is free software This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: • Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. • Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // Standard vcc header // // 16 bpb // // float48 // no int8 // no int64 type utf8str = str type str_r = ucs2char[to] // range type Sema = {} type Mutex = {} type Irpt = {} type Thread = {} type Tid = Thread¢; type int8 = int16 type uint8 = uint16 type FD = {}; type File = FD + {} type Dir = File type Block = {} //enum uint bool = { yes=1, no=0, true=1, false=0 } const bool yes=(bool)1, no=(bool)0 const bool true=(bool)1, false=(bool)0 #include "errno.h" /* Copyright (c) Günter Woigk 2009 - 2015 mailto:kio@little-bat.de This file is free software This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: • Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. • Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // error numbers are small positive numbers: enum uint Err = { ok = 0, // also defined for k1-bus! parameter_error = 1, // also defined for k1-bus! io_error = 2, // also defined for k1-bus! device_not_responding = 3, // also defined for k1-bus! device_busy = 4, not_a_file = 5, not_a_dir = 6, not_a_filesystem = 7, wrong_filetype = 8, file_not_found = 9, file_exists = 10, no_space_left_on_device = 11, end_of_file = 12, dir_not_empty = 13, not_same_device = 14, directories_intersect = 15, data_out_of_range = 16, function_not_supported = 17, null_pointer = 18, // internal_error, out_of_memory = 19 } extern Err errno; const float pi = 3.141592653589793//238462 const float ec = 2.718281828459045//235360 void k1mc_option_procptr_in_rom() = opcode k1mc_option_procptr_in_rom void k1mc_option_procptr_in_ram() = opcode k1mc_option_procptr_in_ram void k1mc_option_return_to_rom() = opcode k1mc_option_return_to_rom void k1mc_option_return_to_ram() = opcode k1mc_option_return_to_ram void k1mc_option_proc_return_to_ram() = opcode k1mc_option_proc_return_to_ram // ____________________________________________________________________ // Math: extern { // int: ulong new (uint hi, uint lo) = opcode nop; int sign (int16) = opcode sign int sign (int32) = opcode sign uint16 abs (int16) = opcode abs uint32 abs (int32) int16 min (int16,int16) = opcode min uint16 min (uint16,uint16) = opcode min int32 min (int32,int32) uint32 min (uint32,uint32) int16 min (int16,int16,int16) = opcode min uint16 min (uint16,uint16,uint16) = opcode min int32 min (int32,int32,int32) = opcode min uint32 min (uint32,uint32,uint32) = opcode min int16 max (int16,int16) = opcode max uint16 max (uint16,uint16) = opcode max int32 max (int32,int32) = opcode max uint32 max (uint32,uint32) = opcode max int16 max (int16,int16,int16) = opcode max uint16 max (uint16,uint16,uint16) = opcode max int32 max (int32,int32,int32) = opcode max uint32 max (uint32,uint32,uint32) = opcode max int16 swap (int16) = opcode swap // revert bytes uint16 swap (uint16) = opcode swap // ((was: SwapBytes)) int32 swap (int32) = opcode swap uint32 swap (uint32) = opcode swap int16 hilo (int16) = opcode hilo uint16 hilo (uint16) = opcode hilo int32 hilo (int32) = opcode hilo uint32 hilo (uint32) = opcode hilo int16 lohi (int16) = opcode lohi uint16 lohi (uint16) = opcode lohi int32 lohi (int32) = opcode lohi uint32 lohi (uint32) = opcode lohi uint16 flip (uint16) = opcode flip // revert bits uint32 flip (uint32) = opcode flip int msbit0 (int16) = opcode msbit0 int msbit0 (uint16) = opcode msbit0 int msbit (int16) = opcode msbit int msbit (uint16) = opcode msbit int16 pow (int16,int) = opcode pow uint16 pow (uint16,int) = opcode pow int32 pow (int32,int) = opcode pow uint32 pow (uint32,int) = opcode pow uint16 random () uint16 random (uint16) uint32 random () uint32 random (uint32) uint16 mul10 (uint16) = opcode Mul10 uint16 exp10 (uint16) = opcode Exp10 uint16 log10 (uint16) = opcode Log10 bool bit15 (uint) = opcode Bit15 // float48: int sign (float) float abs (float) float min (float,float) float max (float,float) // float min (float,float,float) // float max (float,float,float) float round (float) float floor (float) float ceil (float) float integ (float) float fract (float) float random () float random (float) float sin (float) float cos (float) // float tan (float) = opcode tan // float asin (float) = opcode asin // float acos (float) = opcode acos // float atan (float) = opcode atan // float sinh (float) = opcode sinh // float cosh (float) = opcode cosh // float tanh (float) = opcode tanh float exp10 (float) float log10 (float) float exp2 (float) float log2 (float) float expe (float) float loge (float) float exp (float,float) float log (float,float) float pow (float,int) float sqrt (float) } // ____________________________________________________________________ extern // Char: { bool isletter (char) = opcode is_letter bool isdigit2 (char) = opcode is_bin_digit bool isdigit10 (char) = opcode is_dec_digit bool isdigit16 (char) = opcode is_hex_digit uint value10 (char) = opcode digit_value // up to base 36 uint value16 (char) = opcode digit_value // up to base 36 uint value36 (char) = opcode digit_value // up to base 36 } // ____________________________________________________________________ extern // Mem: { void memcpy ( void* z, void* q, uint n ) = opcode memcpy // trad. memcpy, 'ldir' void memcpy ( uint* z, uint* q, uint n ) = opcode memcpy void memcpy ( int* z, int* q, uint n ) = opcode memcpy void memcpy ( char* z, char* q, uint n ) = opcode memcpy void rmemcpy ( void* z, void* q, uint cnt ) = opcode rmemcpy // trad. memcpy, 'lddr' void rmemcpy ( uint* z, uint* q, uint cnt ) = opcode rmemcpy void rmemcpy ( int* z, int* q, uint cnt ) = opcode rmemcpy void rmemcpy ( char* z, char* q, uint cnt ) = opcode rmemcpy void memmove ( void* z, void* q, uint cnt ) = opcode memmove void memmove ( uint* z, uint* q, uint cnt ) = opcode memmove void memmove ( int* z, int* q, uint cnt ) = opcode memmove void memmove ( char* z, char* q, uint cnt ) = opcode memmove void memset ( void* z, byte q, uint n ) = opcode memset void memset ( char* z, char q, uint cnt ) = opcode memset void memset ( uint* z, uint q, uint cnt ) = opcode memset void memset ( int* z, int q, uint cnt ) = opcode memset void memclr ( void* z, uint cnt ) = opcode memclr void memclr ( char* z, uint cnt ) = opcode memclr void memclr ( uint* z, uint cnt ) = opcode memclr void memclr ( int* z, uint cnt ) = opcode memclr void copy ( uint[]¢ q, uint[]¢ z ) = opcode copy void copy ( uint[]¢ q, uint qi, uint[]¢ z, uint zi, uint n ) void copy ( int[]¢ q, uint qi, int[]¢ z, uint zi, uint n ) = void copy(uint[]¢,uint,uint[]¢,uint,uint); void copy ( str¢ q, uint qi, str¢ z, uint zi, uint n ) = void copy(uint[]¢,uint,uint[]¢,uint,uint); void memcompact () = opcode MemCompact uint memgetfree () = opcode MemGetFree void copy_i16_to_i8 ( uint16[]¢ q, uint qi, uint8[]¢ z, uint zi ) void copy_i8_to_i16 ( uint8[]¢ q, uint qi, uint16[]¢ z, uint zi ) void copy_i16_to_i8 ( int16[]¢ q, uint qi, int8[]¢ z, uint zi ) = void copy_i16_to_i8(uint16[]¢,uint,uint8[]¢,uint) void copy_i8_to_i16 ( int8[]¢ q, uint qi, int16[]¢ z, uint zi ) = void copy_i8_to_i16(uint8[]¢,uint,uint16[]¢,uint) } // ____________________________________________________________________ // Strings: extern { // str[]¢ getenv () = opcode getenv; // str[]¢ getargs () = opcode getargs; // void shrinktofit ( str& ) = opcode shrinktofit str_r substr ( str¢ s, int a, int e ) = opcode substr str_r midstr ( str¢ s, int i, int n ) // = opcode midstr str_r midstr ( str¢ s, int i ) // = opcode midstr str_r leftstr ( str¢ s, int n ) // = opcode leftstr str_r rightstr ( str¢ s, int n ) // = opcode rightstr int[to] substr ( int[]¢ s, int a, int e ) = str_r substr ( str¢ s, int a, int e ) int[to] midstr ( int[]¢ s, int i, int n ) = str_r midstr ( str¢ s, int i, int n ) int[to] midstr ( int[]¢ s, int i ) = str_r midstr ( str¢ s, int i ) int[to] leftstr ( int[]¢ s, int n ) = str_r leftstr ( str¢ s, int n ) int[to] rightstr ( int[]¢ s, int n ) = str_r rightstr ( str¢ s, int n ) uint[to] substr ( uint[]¢ s, int a, int e ) = str_r substr ( str¢ s, int a, int e ) uint[to] midstr ( uint[]¢ s, int i, int n ) = str_r midstr ( str¢ s, int i, int n ) uint[to] midstr ( uint[]¢ s, int i ) = str_r midstr ( str¢ s, int i ) uint[to] leftstr ( uint[]¢ s, int n ) = str_r leftstr ( str¢ s, int n ) uint[to] rightstr ( uint[]¢ s, int n ) = str_r rightstr ( str¢ s, int n ) str new ( int n ) = opcode spacestr str spacestr ( int n ) = opcode spacestr str spacestr ( int n, char c ) = opcode spacestr str charstr ( uint c ) = opcode charstr char hexchar ( uint n ) // TODO str hexstr ( uint16 n ) str hexstr ( uint32 n ) str hexstr ( uint16 n, uint digits ) str hexstr ( uint32 n, uint digits ) str binstr ( uint16 n ) = opcode binstr str binstr ( uint32 n ) = opcode binstr str binstr ( uint16 n, uint digits ) = opcode binstr str binstr ( uint32 n, uint digits ) = opcode binstr str binstr ( uint16 n, str¢ d0, str¢ d1 ) = opcode binstr str binstr ( uint32 n, str¢ d0, str¢ d1 ) = opcode binstr str numstr ( int16 n ) str numstr ( uint16 n ) str numstr ( int32 n ) str numstr ( uint32 n ) str numstr ( float n ) int16 numval ( str¢ ) = opcode numval uint16 numval ( str¢ ) = opcode numval int32 numval ( str¢ ) = opcode numval uint32 numval ( str¢ ) = opcode numval float numval ( str¢ ) = opcode numval int find ( int16[]¢, int16, int idx ) = opcode find int find ( int32[]¢, int32, int idx ) = opcode find int find ( uint16[]¢, uint16, int idx ) = opcode find int find ( uint32[]¢, uint32, int idx ) = opcode find int find ( float[]¢, float, int idx ) = opcode find int find ( int16[]¢, int16[]¢, int idx ) = opcode find // int find ( int32[]¢, int32[]¢, int idx ) = opcode find int find ( uint16[]¢, uint16[]¢, int idx ) = opcode find // int find ( uint32[]¢, uint32[]¢, int idx ) = opcode find int rfind ( int16[]¢, int16, int idx ) = opcode rfind int rfind ( int32[]¢, int32, int idx ) = opcode rfind int rfind ( uint16[]¢, uint16, int idx ) = opcode rfind int rfind ( uint32[]¢, uint32, int idx ) = opcode rfind int rfind ( float[]¢, float, int idx ) = opcode rfind int rfind ( int16[]¢, int16[]¢, int idx ) = opcode rfind // int rfind ( int32[]¢, int32[]¢, int idx ) = opcode rfind int rfind ( uint16[]¢, uint16[]¢, int idx ) = opcode rfind // int rfind ( uint32[]¢, uint32[]¢, int idx ) = opcode rfind str min ( str, str ) = opcode min str¢ min ( str¢, str¢ ) = opcode min str max ( str, str ) = opcode max str¢ max ( str¢, str¢ ) = opcode max int16 min ( int16[]¢ ) = opcode min int32 min ( int32[]¢ ) = opcode min uint16 min ( uint16[]¢ ) = opcode min uint32 min ( uint32[]¢ ) = opcode min float min ( float[]¢ ) = opcode min str¢ min ( str[]¢ ) = opcode min int16 min ( int16[to] ) = opcode min int32 min ( int32[to] ) = opcode min uint16 min ( uint16[to] ) = opcode min uint32 min ( uint32[to] ) = opcode min float min ( float[to] ) = opcode min str¢ min ( str[to] ) = opcode min int16 max ( int16[]¢ ) = opcode max int32 max ( int32[]¢ ) = opcode max uint16 max ( uint16[]¢ ) = opcode max uint32 max ( uint32[]¢ ) = opcode max float max ( float[]¢ ) = opcode max str¢ max ( str[]¢ ) = opcode max int16 max ( int16[to] ) = opcode max int32 max ( int32[to] ) = opcode max uint16 max ( uint16[to] ) = opcode max uint32 max ( uint32[to] ) = opcode max float max ( float[to] ) = opcode max str¢ max ( str[to] ) = opcode max /* void sort ( T[]¢ ) = opcode sort void rsort ( T[]¢ ) = opcode rsort void shuffle ( T[]¢ ) = opcode shuffle void flip ( T[]¢ ) = opcode flip void rol ( T[]¢ ) = opcode rol void ror ( T[]¢ ) = opcode ror void sort ( T[to] ) = opcode sort void rsort ( T[to] ) = opcode rsort void shuffle ( T[to] ) = opcode shuffle void flip ( T[to] ) = opcode flip void rol ( T[to] ) = opcode rol void ror ( T[to] ) = opcode ror */ str join ( str[]¢, str¢ ) = opcode join str join ( str[]¢, char ) = opcode join str[] split ( str¢, str¢ ) = opcode split str[] split ( str¢, char ) = opcode split } scope str { str toupper ( str ) = opcode toupper str tolower ( str ) = opcode tolower str escape ( str, char leftquote) = opcode escape str unescape ( str ) = opcode unescape } scope char { char operator+ ( char, int ) = opcode Add } // ____________________________________________________________________ // Time: enum // for timestr { tm_utc = 0, // convert to/from UTC tm_localtime = 1, // convert to/from local time tm_time = 2, // include time tm_date = 4, // include date tm_timezone = 8, // include timezone tm_sec = 16, // include seconds in time tm_msec = 32 // include micro seconds in time } extern { float now () = opcode now str timestr ( float seconds, int localtime ) = opcode timestr // 2011-04-13 09:05:01'033 CEST float timeval ( str¢, int localtime ) = opcode timeval } // ____________________________________________________________________ // Multithreading: type Thread = { // dispatcher data: int state1; // running, willing, suspended, semashed, timeshed int state2; // blocking list int prio; // actual priority: lower is better prio = log2(reaktionszeit/sec) int prio_org; // nominal priority (most times same as prio) Tid next1,prev1; // list1: willing, timeshed, suspended, scrapped (or running) Tid next2,prev2; // list2: blocking Sema or Mutex void* blocker; // Sema, Mutex or Irpt for which thread is waiting float time; // alarm time for which thread is sheduled Mutex* mutexes; // linked list of mutexes blocked by this thread // interpreter data: uint*[] rstack; // return stack & context heap int[] vstack; // thread state: int* context0; int* context1; uint* ip; // instruction pointer uint** rp; // return stack pointer int* vp; // variables stack pointer int* gp; // only s_node: global data base int _errno; } Tid self () = opcode self int vfree () = opcode vfree int rfree () = opcode rfree void freeze (bool) = opcode freeze // void spawn (void(*) fu,*) = opcode spawn // built-in // void spawn (void(*) fu,*),prio,vstack,rstack=opcode spawn // built-in void termi () = opcode termi // self void termi (Tid) = opcode termi void suspend () = opcode suspend // self void suspend (Tid) = opcode suspend void resume (Tid) void wait () = opcode wait // until next interrupt void wait (float sec) // = opcode wait void shedule (float when) = opcode shedule void busywait (uint usec) = opcode busywait type Sema = // note: i386_64: struct size alignment 8 bytes { Tid waiters int count // available resources } scope Sema { void request (Sema¢) = opcode request void release (Sema¢) = opcode release bool tryrequest (Sema¢) = opcode tryrequest bool tryrequest (Sema¢, float timeout) = opcode tryrequest // Sema init (Sema) = opcode nop Sema copy (Sema) = opcode copy Sema kill (Sema) = opcode kill void clear (Sema¢ s) = opcode mutexclear // inline { s.count=0; } void add (Sema¢ s, int n) = opcode release } type Mutex = { Tid waiters Tid owner Mutex¢ next,prev } scope Mutex { void lock (Mutex¢) = opcode lock void unlock (Mutex¢) = opcode unlock bool trylock (Mutex¢) = opcode trylock bool trylock (Mutex¢, float timeout) = opcode trylock // Mutex init (Mutex) = opcode nop // default c'tor is ok Mutex copy (Mutex) = opcode copy // Mutex kill (Mutex) = opcode kill // } type Irpt = { Tid waiters int count } scope Irpt { void wait (Irpt¢) = opcode wait void wait (Irpt¢,float timeout) = opcode wait void trigger (Irpt¢) = opcode trigger void clear (Irpt¢ i) = opcode semaclear // inline { i.count = 0; } Irpt copy (Irpt) = opcode copy Irpt kill (Irpt) = opcode kill } // ____________________________________________________________________ // Debug: extern { str errorstr (int error) = opcode errorstr str errorstr () = opcode errorstr void log_hp () = opcode LogHP void trace () = opcode Trace // microcode trace void tron () = opcode Tron // millicode trace void troff () = opcode Troff void log_cc () = opcode LogCC void log (char) = opcode logchar void lognum (int) = opcode lognum void log (str) = opcode logstr void log (str¢) = opcode logstr void logmem () = opcode LogMem void OMEM () = opcode oomem void TODO () = opcode todo void abort () = opcode abort void abort (str msg) void IERR () = opcode abort void PANIC () = opcode panic void PANIC (str msg) void setledred () = opcode SetLedRed void setledyel () = opcode SetLedYel void setledgrn () = opcode SetLedGrn void clrledred () = opcode ClrLedRed void clrledyel () = opcode ClrLedYel void clrledgrn () = opcode ClrLedGrn uint get_hp () = opcode PshHP }; // ____________________________________________________________________ // Devices: void select (int) = opcode select void set_intmask () = opcode SetIntMask void deselect () = opcode deselect void clear_error (); // clear errno #include "SerialDevice.h" /* Copyright (c) Günter Woigk 2009 - 2015 mailto:kio@little-bat.de This file is free software This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: • Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. • Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "Device.h" /* Copyright (c) Günter Woigk 2009 - 2015 mailto:kio@little-bat.de This file is free software This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: • Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. • Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "FD.h" /* Copyright (c) Günter Woigk 2009 - 2015 mailto:kio@little-bat.de This file is free software This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: • Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. • Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "stdc.h" #include "options.h" // Class Hierarchy: // // subtypes: // // FD // +-- Node // +-- Device // | +-- SerialDevice // | +-- BlockDevice // | +-- I2cBlockDevice // | +-- NullBlockDevice // | +-- FileBlockDevice // +-- File // +-- Dir (Dir==File) enum uint NodeType = { t_node = 0, // node in ram t_dir = 1, // directory with 8- or 16-bit entries (depending on device width) t_file = 2, // regular 8-bit or 16-bit file t_block = 3, // block device with int8[] or int16[] buffer t_ser = 4, // serial 8-bit or 16-bit device t_erased, // erase file in Dir list // t_blockfile, // file device, driver built-in TODO t_none }; /* ========================================================= Classes: ========================================================= */ // File Descriptor Base Class: // type FD = { NodeType nodetype; str name; FD¢ parent; bool wide; // 0=uint8[], 1=uint16[] } // Node in Ram: // type Node = FD + { FD[] items; } // Array of FDs: // type FDs = FD[]; /* ========================================================= Methodes: ========================================================= */ scope FDs { void append (FD[]¢,FD) = opcode AppendChar; // void append(str¢, char); } scope Node { extern { str[] entries (Node¢); // get list of all child names FD¢ find (Node¢, str¢ name); // get the named child void append (Node¢, FD); // append child void remove (Node¢, FD¢); // remove child } } // ________________________________________________ // scope FD { enum // für open(name,HOW) { WIDE = 1<<0, // 1<<0 wide, else 8-bit DIR = 1< 8- or 16-bit depending on file width! uint readbyte (FD¢) // sets errno void writebyte (FD¢, uint) // sets errno uint32 read2bytes (FD¢) // sets errno void write2bytes (FD¢, uint32 n) // sets errno void readbytes (FD¢, uint[]¢) // sets errno void writebytes (FD¢, uint[]¢) // sets errno void readbytes (FD¢, int[]¢) = void readbytes(FD¢,uint[]¢) void writebytes (FD¢, int[]¢) = void writebytes(FD¢,uint[]¢) // read / write 16-bit data: void readdata (FD¢, uint16[]¢) // sets errno void writedata (FD¢, uint16[]¢) // sets errno void readdata (FD¢, int16[]¢) = void readdata(FD¢,uint16[]¢) void writedata (FD¢, int16[]¢) = void writedata(FD¢,uint16[]¢) // read / write int15: // internet byte order: hi before lo // on a wide file this reads/writes uint16 // on a 8-bit file this reads/writes 1 or 2 bytes depending on value uint16 read15 (FD¢ z) // sets errno void write15 (FD¢ z, uint16) // sets errno // read / write int16: // internet byte order: hi before lo uint16 read (FD¢) // sets errno void write (FD¢, uint16) // sets errno int16 read (FD¢) = uint16 read(FD¢) void write (FD¢, int16) = void write(FD¢,uint16) // read / write int24: // internet byte order: hi before lo uint32 read24 (FD¢) // sets errno void write24 (FD¢, uint32) // sets errno // read / write int32: // internet byte order: hi before lo uint32 read (FD¢) // sets errno void write (FD¢, uint32) // sets errno int32 read (FD¢) = uint32 read(FD¢) void write (FD¢, int32) = void write(FD¢,uint32) // read / write float: // internet byte order: exp before mant.hi before mant.lo float read (FD¢) // sets errno void write (FD¢, float) // sets errno // natural size of file: str read (FD¢) // sets errno: int15-length prefixed p-string void write (FD¢, str¢) // sets errno: int15-length prefixed p-string str getstr (FD¢) // sets errno; void putstr (FD¢, str) // sets errno; void putstr (FD¢, str¢) = void writebytes(FD¢,int[]¢) char getchar (FD¢) = uint readbyte(FD¢) void putchar (FD¢, uint) = void writebyte(FD¢,uint) } // extern } // scope FD // ________________________________________________ // Globals: extern { Node root; // root of it all FD stdin; FD stdout; FD stderr; Err errno; void init_devices(); #if include_filesystem void mount (str¢) // sets errno void unmount (str¢, bool force) // sets errno NodeType nodetype (str¢) // sets errno FD open (str path, uint how) // sets errno File newfile (str¢, bool wide) // sets errno Dir newdir (str¢) // sets errno uint[] readfile (str¢) // sets errno, uses file's width void writefile (str¢,uint[]¢,bool wide) // sets errno void remove (str¢) // sets errno bool isfile (str¢) // sets errno bool isdir (str¢) // sets errno void swapfiles (str¢, str¢) // sets errno void renamefile (str¢, str¢, bool replace ) // sets errno File newtempfile (str¢ dirpath, bool wide ) // sets errno #endif } // ________________________________________________ // // opaque driver data // die verschiedenen K1-Bus-Device-Treiber haben alle ein DriverData-Struct. // dessen interner Aufbau ist unbestimmt. // Im Microcode-Rom wird dafür der Struct DrvrData verwendet. // Da er compiler-technisch nicht leer sein kann, tun wir was rein. // Da das I2C-BlockDevice später auch ein DrvrData benötigt, // tun wir schon mal was rein, was dafür passt. // type DrvrData = { uint selectmask; } type t_getctl = uint(DrvrData¢ channel, uint ioctl_fu); type t_setctl = void(DrvrData¢ channel, uint ioctl_fu, uint value); type t_getc = uint(DrvrData¢ channel); type t_putc = void(DrvrData¢ channel, uint char); type t_gets = uint(DrvrData¢ channel, uint[]¢ data, uint a, uint e); type t_puts = uint(DrvrData¢ channel, uint[]¢ data, uint a, uint e); type t_readblocks = Err (DrvrData¢ channel, uint32 startblock, uint[]¢ data, uint a, uint e); type t_writeblocks = t_readblocks; type t_blkio = t_readblocks; // ________________________________________________ // type Device = FD + { uint flags; // flags from eeprom block "0", e.g. device class DrvrData¢ drvrdata; // driver data for this subdevice t_getctl p_getctl; // driver getctl() proc t_setctl p_setctl; // driver setctl() proc } scope Device { extern uint getctl ( Device¢, uint ioctl_fu ) // -> p_getctl extern void setctl ( Device¢, uint ioctl_fu, uint n ) // -> p_setctl } type SerialDevice = Device + { t_getc p_getc; t_gets p_gets; t_putc p_putc; t_puts p_puts; } scope SerialDevice { extern { // test non-blocking free: bytes uint getavail (SerialDevice¢); // pre-test input for non-blocking uint getfree (SerialDevice¢); // pre-test output for non-blocking // read / write bytes (natual size): uint readbyte (SerialDevice¢); void writebyte (SerialDevice¢, uint); uint readbytes (SerialDevice¢, uint[]¢, uint a, uint e); uint writebytes (SerialDevice¢, uint[]¢, uint a, uint e); uint readbytes (SerialDevice¢, uint[…]) = opcode SerialDevice__readbytes__12SerialDeviceC_6uint16AEC_6uint16_6uint16_6uint16; uint writebytes (SerialDevice¢, uint[…]) = opcode SerialDevice__writebytes__12SerialDeviceC_6uint16AEC_6uint16_6uint16_6uint16; void readbytes (SerialDevice¢, uint[]¢); void writebytes (SerialDevice¢, uint[]¢); void writebytes (SerialDevice¢, int[]¢) = void writebytes(SerialDevice¢,uint[]¢); void readbytes (SerialDevice¢, int[]¢) = void readbytes (SerialDevice¢,uint[]¢); // read / write 16 bit data: void readdata (SerialDevice¢, uint16[]¢); // -> readbytes + 8:16 void writedata (SerialDevice¢, uint16[]¢); // -> 16:8 + writebytes void writedata (SerialDevice¢, int16[]¢) = void writedata(SerialDevice¢,uint16[]¢ ); void readdata (SerialDevice¢, int16[]¢) = void readdata (SerialDevice¢,uint16[]¢ ); // read / write bytes (natural size): char getchar (SerialDevice¢) = uint readbyte (SerialDevice¢); void putchar (SerialDevice¢, uint) = void writebyte (SerialDevice¢, uint); str getstr (SerialDevice¢); void putstr (SerialDevice¢, str¢) = void writebytes(SerialDevice¢,uint[]¢ ); }; } // ________________________________________________ // Globals: extern { SerialDevice new (str¢ name, uint devclass, DrvrData¢, t_getctl, t_setctl, t_getc, t_gets, t_putc, t_puts ); } #include "globals.cc.h" /* Copyright (c) Günter Woigk 2009 - 2015 mailto:kio@little-bat.de This file is free software This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: • Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. • Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "options.h" #include "errno.h" type Node = {}; type FD = {}; // ================================================= // Global Data starting at $0000 // ================================================= // globals defined in "globals.asm" // ================================================= extern { // Interrupts: uint* int_vector; // interrupt vectors[16] uint int_mask; // enable mask for installed handlers // Memory: uint* gdata_ptr; // allocation pointer for zeropage global data uint* gcode_ptr; // start of space for new words uint* hp_base; // bottom of data heap uint* sp_base; // top of return stack uint* mem_data_start; // Start of dynamic data blocks uint* mem_data_end; // Start of free memory between data and pointers uint* mem_ptr_start; // Start of dynamic data pointers uint* mem_free_ptr; // Pointer to linked chain of free global pointers // uint* mem_ptr_end; // End of local data pointers uint* mem_end; // Time: uint32 current_time; // current time in UTC [seconds] uint32 current_microsec; // µsecond akku uint microsecs_per_int; // µseconds per timer interrupt // i/o: Node root; FD stdin; // FD for standard input device FD stdout; // FD for standard output device FD stderr; // FD for standard error device Err errno; #if include_sio_driver_in_rom uint sio_getctl_proc; uint sio_setctl_proc; uint sio_getc_proc; uint sio_gets_proc; uint sio_putc_proc; uint sio_puts_proc; uint sio_irpt_proc; SioData sio_channel_A; *** error *** symbol not found: SioData SioData sio_channel_B; *** error *** symbol not found: 'SioData' uint16 sio_selectmask; uint8 IMR_value; // current value of interrupt mask register IMR uint8 OPCR_value; // current value of output port control register OPCR #endif #if include_filesystem str trashname; // name for trash dir & files = ".trash" #endif // Misc: uint null; // const: 0 uint opcode_Ret; // opcode Ret: return_to_millicode // End of Globals: const uint mem_globs_end; *** error *** '=' expected (;) } *** error *** value expected ('}') // ============================================== // descriptive eeprom chunks: // ============================================== #if 0 #define block_0 "K1D1jg75" // magic bytes #define block_1 0b00010111 /* DEVCLASS_1: in,out,ser,tty */ \ 0b00000100 /* DEVCLASS_2: timer */ \ 0b00000000 /* DEVREQ: */ \ 64 /* IOSPEED 64/128 = 0.5µs */ \ 6 /* INTPRIO 1/2^6 = 1/64s */ \ 2 /* SUBDEVICES 2 */ #define block_2 "sio" // device name #define block_3 "DualSio" // visual name #define block_4 "0.4" // version #define block_5 "(c) kio@little-bat.de 2012-2013" // short copyright #endif // ============================================== // UART registers: // ============================================== // UART clock: #define XTAL 7372000 enum uint8 // READ register: { MR0A = 0, // Mode Registers A MR1A = 0, MR2A = 0, SRA = 1, // Status Register A UNUSED1, // RXA = 3, // Receive Buffer A IPCR = 4, // Input Port Change Register ISR = 5, // Interrupt Status Register CUR = 6, // Counter/Timer Upper Register CLR = 7, // Counter/Timer Lower Register MR0B = 8, // Mode Registers B MR1B = 8, MR2B = 8, SRB = 9, // Status Register B UNUSED2, // RXB = 11, // Receive Buffer B GPR = 12, // General Purpose Register IPR = 13, // Input Port Register STCR = 14, // Start C/T Command SPCR = 15 // Stop C/T Command }; enum uint8 // WRITE register: { MR0A = 0, // Mode Registers A CSRA = 1, // Clock Select Register A CRA = 2, // Command Register A TXA = 3, // Transmitter Buffer A ACR = 4, // Auxiliary Control Register IMR = 5, // Interrupt Mask Register CTPU = 6, // C/T Preload Value Upper Register CTPL = 7, // C/T Preload Value Lower Register MR0B = 8, // Mode Registers B CSRB = 9, // Clock Select Register B CRB = 10, // Command Register B TXB = 11, // Transmitter Buffer B GPR = 12, // General Purpose Register OPCR = 13, // Output Port Configuration Register SOPR = 14, // Set Output Port Register ROPR = 15 // Reset Output Port Register }; enum uint8 { // bits in status register SRA & SRB: mSR_RX_ready = 1, mSR_RX_full = 2, mSR_TX_ready = 4, mSR_TX_empty = 8, mSR_RX_overrun = 16, mSR_RX_parity = 32, mSR_RX_framing = 64, mSR_RX_break = 128, // bits in interrupt mask register IMR and interrupt status register ISR mIMR_TXA_ready = 1, mIMR_RXA_ready = 2, mIMR_RXA_break = 4, mIMR_CT_ready = 8, mIMR_TXB_ready = 16, mIMR_RXB_ready = 32, mIMR_RXB_break = 64, mIMR_IP_changed = 128, // bits in SOPR, ROPR: mOPR_RTSA = 1, // RTSA or Inverter Control for CLKA.out (normally asserted (low) -> not inverted) mOPR_RTSB = 2, // RTSB or Inverter Control for CLKB.out (normally asserted (low) -> not inverted) mOPR_CLKA = 4, // CLKA or Inverter Control for RTSA (should be asserted (low) -> not inverted) mOPR_CLKB = 8, // CLKB or Inverter Control for RTSB (should be asserted (low) -> not inverted) mOPR_CTLA = 16, // pin header mOPR_CTLB = 32, // pin header mOPR_INVA = 64, // CLKA.in.INV Inverter Control for CLKA.in und CTSA (normally asserted (low) -> not inverted) mOPR_INVB = 128 // CLKB.in.INV Inverter Control for CLKB.in und CTSB (normally asserted (low) -> not inverted) }; // Output Port Configuration Register OPCR: const uint8 OPCR_value = 0b00<<0 // OP2/CLKA = normal port mode + 0b00<<2 // OP3/CLKB = normal port mode + 0b0000<<4; // OP4,5,6,7 = normal port mode *** error *** name 'OPCR_value' already used for var OPCR_value // Output Port Value: SOPR und ROPR: const uint8 SOPR_value = mOPR_RTSA // assert RTSA (just in case) + mOPR_RTSB // assert RTSB (just in case) + mOPR_CLKA // Inverter Control for RTSA: asserted = 0 = don't invert + mOPR_CLKB // Inverter Control for RTSB: asserted = 0 = don't invert + mOPR_CTLA // assert aux signal on pin header A + mOPR_CTLB // assert aux signal on pin header B + mOPR_INVA // Inverter Control for input signals port A: asserted = 0 = don't invert + mOPR_INVB; // Inverter Control for input signals port B: asserted = 0 = don't invert const uint8 ROPR_value = 0; // Interupt Mask Register IMR: const uint8 IMR_value = mIMR_TXA_ready // TxA ready + mIMR_RXA_ready // RxA ready + !mIMR_RXA_break // RxA break change + mIMR_CT_ready // C/T expired + mIMR_TXB_ready // TxB ready + mIMR_RXB_ready // RxB ready + !mIMR_RXB_break // RxB break change + !mIMR_IP_changed; // Input port change *** error *** name 'IMR_value' already used for var IMR_value // Auxilliary Control Register: const uint8 ACR_value = 0b0000 // 4 bits: selects which bits of the input port change register (IPCR) // cause the interrupt status register (ISR) bit-7 to be set. + 0b111<<4 // 3 bits: Counter/Timer Mode and Clock Source: // Crystal or External Clock (XTAL1/Clk) Divided by 16 + 0<<7; // Baud rate table select // Mode Register 0: const uint8 MR0_value = 0<<0 // 1: baudrate table 1 MUST BE ORED IN! + 0<<1 // FACTORY TEST MODE + 0<<2 // 1: baudrate table 2 MUST BE ORED IN! + 0<<3 // NOT USED + 0b10<<4 // TxD irpt trigger level: 12 of 16 bytes in FIFO are empty + 0 << 6 // RxD irpt trigger level: 6 bytes in FIFO ((+MR1.bit6)) + 1 << 7; // receiver timeout watchdog timer // Mode Register 1: const uint8 MR1_value = 0b11 << 0 // 8 bit + 0 << 2 // if not in multidrop mode: 0 = even parity + 0b10 << 3 // no parity + 0 << 5 // data error mode: 0 = single character + 1 << 6 // RxD trigger level: 6 bytes in FIFO ((+MR0.bit6)) + 0 << 7; // no receiver RTS flow control // Mode Register 2: const uint8 MR2_value = 0b0111 << 0 // stop bit length: 1.000 + 0 << 4 // no transmitter CTS flow control + 0 << 5 // no auto transmit RTS + 0b00 << 6; // no loopback mode // ============================================== // K1-Bus const values: // ============================================== const { // buffer size: uint8 obusz = 1<<4; // output buffer size; must be 2^n uint8 ibusz = 1<<4; // input buffer size; must be 2^n uint8 obumask = obusz-1; uint8 ibumask = ibusz-1; // special characters: uint8 xon = 17; uint8 xoff = 19; // default baudrate: uint8 baud_9600 = 9600/2400; uint8 baud_57k6 = 57600/2400; // ioctl function codes: uint8 c_reset = 0; // 00 + set reset uint8 c_speed = 1; // 01 + set/get set/get serial speed * 100 uint8 c_hwhsk = 2; // 02 + set/get set/get HW handshake on/off uint8 c_swhsk = 3; // 03 + set/get set/get SW handshake state for send data on/off uint8 c_flushin = 4; // 04 + set flush uint8 c_availin = 4; // 04 + get get avail bytes in input buffer uint8 c_flushout = 5; // 05 + set flush uint8 c_availout = 5; // 05 + get get avail space in output buffer uint8 c_reserved = 6; // 06 reserved uint8 c_pinhdrctl = 7; // set custom ioctl fu uint8 c_clk_hsk = 8; // set+get custom ioctl fu }; // ============================================== // custom data types: // Block Type "A - TYPEDEFS" // ============================================== // SioData contains all data for one channel: // type SioData = { uint8 channel; // 0 = channel A; 1 = channel B // settings: bool hw_handshake; bool sw_handshake; uint8 baudrate; // baudrate / 2400 uint8 clk_handshake; // bit.0: emit TX clock // bit.1: emit RX clock // bit.2: invert clocks // bit.3: may be set // buffers: uint8[] ibu; // input buffer uint8[] obu; // output buffer uint8 ibuwi; // input buffer write index uint8 iburi; // input buffer read index uint8 obuwi; // output buffer write index uint8 oburi; // output buffer read index // state: bool xoff_received; bool xoff_sent; // const: ports and bit masks: uint8 SR; // SRA+channel<<3 channel's status register uint8 IO; // RXA+channel<<3 channel's data i/o register uint8 mIMR_RX_ready; // 1<<(bIMR_RX_ready+channel<<2) channel's receiver ready interrupt bit mask uint8 mIMR_TX_ready; // 1<<(bIMR_TX_ready+channel<<2) channel's transmitter ready interrupt bit mask } // ============================================== // global data: // Block Type "B - GLOBALS" // ============================================== extern { SioData sio_channel_A; SioData sio_channel_B; uint16 sio_selectmask; uint8 IMR_value; // current value of interrupt mask register IMR uint8 OPCR_value; // current value of output port control register OPCR }; // ============================================== // procedures: // Block Type "C - PROCDEF" (multiple) // these are sorted by the compiler before writing to file // ============================================== scope SioData { uint avail_in(SioData¢ channel) { return channel.ibuwi - channel.iburi; } uint avail_out(SioData¢ channel) { return obusz - ( channel.obuwi-channel.oburi ); } /* handle interrupt for this channel: in: interrupts disabled & device selected */ void irpt( SioData¢ this ) { uint8 c; uint8 SR = this.SR; // port addr uint8 IO = this.IO; // port addr // Receive data: do { while( in(SR) & mSR_RX_ready && this.ibuwi-this.iburi now we rely on the UART internal FIFO buffer if( !this.xoff_sent ) { out(IO,xoff); *** error *** symbol not found: 'out' this.xoff_sent = true; } } else // ibu[] in ram has free space { if( this.xoff_sent ) { out(IO,xon); *** error *** symbol not found: 'out' this.xoff_sent = false; } } } // Send data: do { while( in(SR) & mSR_TX_ready && this.obuwi!=this.oburi && !this.xoff_received ); *** error *** symbol not found: 'in' out(IO,this.obu[(this.oburi++)&obumask]); *** error *** symbol not found: 'out' } // enable / disable interrupts: if(this.ibuwi-this.iburi==ibusz) IMR_value &= ~this.mIMR_RX_ready; // ibu[] full -> disable rx irpt else IMR_value |= this.mIMR_RX_ready; if(this.obuwi==this.oburi || this.xoff_received) IMR_value &= ~this.mIMR_TX_ready; // obu[] empty -> disable tx irpt else IMR_value |= this.mIMR_TX_ready; out(IMR,IMR_value); *** error *** symbol not found: 'out' } /* set baudrate: in: interrupts disabled & device selected validates baudrate handles clocks on handshake lines !! does not reset the channel !! */ void set_baudrate( SioData¢ this, uint8 baudrate ) { uint8 chx8 = this.channel << 3; /* calculate UART register value for baudrate*2400: %0000000x 1 *2400 = 2400 %00000010 2 *2400 = 4800 %0000010x 4 *2400 = 9600 %000010xx 8 *2400 = 19k2 %00010xxx 16 *2400 = 38k4 %0010xxxx 32 *2400 = 76k8 %010xxxxx Illegal, returns 9600 %10xxxxxx Illegal, returns 9600 %00000011 3 *2400 = 7200 %0000011x 6 *2400 = 14k4 %000011xx 12 *2400 = 28k8 %00011xxx 24 *2400 = 57k6 %0011xxxx 48 *2400 = 115k2 %011xxxxx 96 *2400 = 230k4 %11xxxxxx 192*2400 = 460k8 */ #define V(MR0,CSR) (MR0_value+MR0)*256+CSR*17 // N.hi = MR0 register value // N.lo = CSR register value uart_values_for_baudrate := (uint16[]) *** error *** symbol not found: 'uart_values_for_baudrate' { V(0,0b0110), V(0,0b1000), V(0,0b1001), V(0,0b1011), // 2400, 4800, 9600, 19k2 V(4,0b0011), V(0,0b1100), V(0,0b1001), V(0,0b1001), // 38k4, 76k8, 9600, 9600 V(0,0), V(1,0b0101), V(1,0b0110), V(1,0b1000), // 0, 7200, 14k4, 28k8 V(1,0b1001), V(1,0b1011), V(4,0b0110), V(1,0b1100) // 57k6,115k2,230k4,460k8 }; // UART bytes for baudrate: uint8 i = msbit(baudrate); // 0 .. 7 uint8 t = i && baudrate>>(i-1) & 1; // table: 0=2*1200 series, 1=3*1200 series uint v = uart_values_for_baudrate[t<<3+i]; *** error *** symbol not found: 'uart_values_for_baudrate' // set SioData.baudrate to actually used value: this.baudrate = t ? 3<<(i-1) : i<6 ? 1< = RTSx not inverted // CTLx = no change // INVx = 0 = CTSx not inverted // uint8 ch = this.channel; // out(SOPR,(mOPR_CLKA+mOPR_INVA)< can be used 'as is' by hardware handshake selects internal or external clock for TX and RX by call to set_baudrate !! does not reset the channel !! */ void set_clock_handshake( SioData¢ this, uint8 flags ) { uint8 ch = this.channel; uint8 chx2 = ch << 1; if( this.clk_handshake != flags ) { // TODO: switch of hw hsk //if(f) this.set_hw_handshake(false); this.clk_handshake = flags; // TX clock senden oder empfangen? // bit.1: TXD: emit clk.out if(flags&3) OPCR_value |= 3< invert *** error *** symbol not found: 'out' // RTS und receiver hsk inverter := 0 --> !invert this.set_baudrate(this.baudrate); } } /* reset receiver and/or transmitter in: interrupts disabled & device selected does not change baudrate or mode */ void reset( SioData¢ this, bool tx, bool rx ) { uint8 CR = CRA + this.channel << 3; if(rx) { out(CR, 0x20); // reset receiver this.xoff_sent = false; this.ibuwi = this.iburi; } if(tx) { out(CR, 0x30); // reset transmitter this.xoff_received = false; this.oburi = this.obuwi; } out(CR, 0x40); // reset error status: Clears channel, break, parity, and over-run error bits in the status register. // re-enable receiver and transmitter: out(CR, 1 << 0 // enable receiver + 1 << 2); // enable transmitter } /* init channel */ void init(SioData¢ this, uint8 ch) { this.channel = ch; // 0=A, 1=B this.ibu := alloc uint8[ibusz](); // input buffer this.obu := alloc uint8[obusz](); // output buffer // this.set_baudrate(baud_9600); this.set_baudrate(baud_57k6); uint8 ch2 = ch << 2; this.mIMR_RX_ready = mIMR_RXA_ready< write more chars or disable irpt // ISR.1 Receiver A: FIFO filled beyond high water mark: --> read more chars or disable irpt // ISR.2 Receiver A: break state changed: --> write a channel A reset break change interrupt command (CRA bits 7-4 = 0x5) // this interrupt is not enabled // ISR.3 Counter/Timer: C/T ready: --> read the stop counter command SPCR // the C/T is only started when systemTimer(delay,proc) was called // ISR.4 Transmitter B: FIFO fallen below low water mark: --> write more chars or disable irpt // ISR.5 Receiver B: FIFO filled beyond high water mark: --> read more chars or disable irpt // ISR.6 Receiver B: break state changed: --> write a channel B reset break change interrupt command (CRB bits 7-4 = 0x5) // this interrupt is not enabled // ISR.7 Input port changed: --> read the input port change register. (not used, should not happen) // this interrupt is not enabled // Check timer interrupt: if(in(ISR) & mIMR_CT_ready) // the C/T is only started when systemTimer(delay,proc) was called { if(in(SPCR)){} // note: in timer mode the stop C/T command only resets interrupt and does not stop the C/T timer(); } // Handle two SIO ports: sio_channel_A.irpt(); sio_channel_B.irpt(); } // set a device option // required function for Serial Device // void SIO_SETCTL( SioData¢ channel, uint8 fu, uint value ) { k1mc_option_proc_return_to_ram(); // k1eeAsm option: use RDROP_RET for return opcode select(sio_selectmask); switch(fu) { // case c_pinhdrctl: TODO(); case c_clk_hsk: channel.set_clock_handshake(value); break; case c_reset: channel.reset(yes,yes); break; case c_speed: channel.set_baudrate(value/24); break; case c_hwhsk: channel.set_hw_handshake(value!=0); break; case c_swhsk: channel.set_sw_handshake(value!=0); break; case c_flushin: channel.reset(no,yes); break; case c_flushout:channel.reset(yes,no); break; } ei(); } // get a device state // required function for Serial Device // uint SIO_GETCTL( SioData¢ channel, uint8 fu ) { k1mc_option_proc_return_to_ram(); // k1eeAsm option: use RDROP_RET for return opcode switch(fu) { case c_speed: return channel.baudrate*24; // baudrate/100 case c_hwhsk: return channel.hw_handshake; case c_swhsk: return channel.sw_handshake; case c_clk_hsk: return channel.clk_handshake; case c_availin: return channel.avail_in(); case c_availout:return channel.avail_out(); default: return 0; // don't know } } // get 1 character // required function for Serial Device // blocking // uint SIO_GETC( SioData¢ channel ) { k1mc_option_proc_return_to_ram(); // k1eeAsm option: use RDROP_RET for return opcode // wait until byte available: blocking do{ until channel.avail_in(); wait(); } // get byte. be careful not to increment iburi // before actually having read the byte! uint c = channel.ibu[channel.iburi & ibumask]; // if the buffer was 100% full, then there may be bytes left in the UART's queue. // if no more bytes arrive (for a while) and no other interrupts from this UART happen, // then they won't be read (for a while). Therefore kick irpt(): if(channel.iburi++ == channel.ibuwi - ibusz) { select(sio_selectmask); channel.irpt(); ei(); } return c; } // write 1 character // required function for Serial Device // blocking // void SIO_PUTC( SioData¢ channel, uint8 c ) { k1mc_option_proc_return_to_ram(); // k1eeAsm option: use RDROP_RET for return opcode // wait until byte available: blocking do{ until channel.avail_out(); wait(); } // store byte. be careful not to increment obuwi // before actually having written the byte! channel.obu[channel.obuwi & obumask] = c; // if the buffer was 100% empty, then there will be no 'sender queue empty' interrupt. // if no other interrupts from this UART happen (for a while), // then this byte won't be sent (for a while). Therefore call irpt(): if(channel.obuwi++ == channel.oburi) { select(sio_selectmask); channel.irpt(); ei(); } } // get string // required function for Serial Device // returns num bytes actually read // non-blocking // uint SIO_GETS( SioData¢ channel, uint8[]¢ bu, uint i, uint n ) { k1mc_option_proc_return_to_ram(); // k1eeAsm option: use RDROP_RET for return opcode // get count of available bytes. n = min(n,channel.avail_in()); // copy them to provided buffer: copy( channel.ibu, channel.iburi&ibumask, bu, i, n); // increment iburi *after* actually having copied the data // and *before* eventually kicking the interrupt channel.iburi += n; // if the buffer was 100% full, then there may be bytes left in the UART's queue. // if no more bytes arrive (for a while) and no other interrupts from this UART happen, // then they won't be read (for a while). Therefore call irpt(): if(channel.iburi-n == channel.ibuwi - ibusz) { select(sio_selectmask); channel.irpt(); ei(); } return n; } // write string // required function for Serial Device // returns num bytes actually written // non-blocking // uint SIO_PUTS( SioData¢ channel, uint8[]¢ bu, uint i, uint n ) { k1mc_option_proc_return_to_ram(); // k1eeAsm option: use RDROP_RET for return opcode // get count of available space. n = min(n,channel.avail_out()); // copy them from provided buffer: copy(bu, i, channel.obu, channel.obuwi&obumask, n); // increment obuwi *after* actually having copied the data // and *before* eventually kicking the interrupt channel.obuwi += n; // if the buffer was 100% empty, then there will be no 'sender queue empty' interrupt. // if no other interrupts from this UART happen (for a while), // then the new data won't be sent (for a while). Therefore call irpt(): if(channel.obuwi-n == channel.oburi) { select(sio_selectmask); channel.irpt(); ei(); } return n; } // ___________________________________________________ // initialize: // called from init_devices() ((Millicode)) // called with interrupts disabled and device selected // void sio_init( uint select_mask ) { sio_selectmask = select_mask; IMR_value = IMR_value; OPCR_value = OPCR_value; if(OPCR_value) out(OPCR,OPCR_value); // 0 if(SOPR_value) out(SOPR,SOPR_value); // 0xff if(ROPR_value) out(ROPR,ROPR_value); // 0 if(ACR_value) out(ACR,ACR_value); // create, init and enable channels: sio_channel_A := alloc SioData(); sio_channel_B := alloc SioData(); sio_channel_A.init(0); sio_channel_B.init(1); // start system timer interrupt // 100 Hz => period = 10000 µs // CTP_value period // --------- = ------- <=> CTP_value = period * XTAL / 32e6 = 10000 * 7372000 / 32e6 = 2304 // XTAL/16/2 1000000 <=> period = CTP_value / XTAL * 32e6 = 2304 / 7372000 * 32e6 = 10001 out(CTPU,9); /* out(CTPL,0); */ // set C/T preload value to 2304 microsecs_per_int = 10001; // store the actual period: uint foo = in(STCR); // start timer: // enable interrupts in the UART: out(IMR,IMR_value); }