diff --git a/.gitignore b/.gitignore index 103618f..10e7f57 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,7 @@ -*.s +pcomp/*.s +progs/*.s +tests/*.s +examples/*.s *.o *.exe *.bin @@ -10,6 +13,7 @@ *.sasmout *.lib *.img +*.mem *.lsym *.zip go.sum @@ -17,5 +21,12 @@ sine.pas graph.pas graph2.pas chase.pas -*.img !runtime.s +**/tridoracpu.*/ +rtl/arty-a7/mig_dram_0/_tmp/* +rtl/arty-a7/mig_dram_0/doc/* +rtl/arty-a7/mig_dram_0/mig_dram_0* +rtl/arty-a7/mig_dram_0/xil_txt.* +rtl/arty-a7/mig_dram_0/*.veo +rtl/arty-a7/mig_dram_0/*.tcl +rtl/arty-a7/mig_dram_0/*.xml diff --git a/examples/LICENSES.md b/examples/LICENSES.md index 32ad7df..8992b88 100644 --- a/examples/LICENSES.md +++ b/examples/LICENSES.md @@ -1,3 +1,5 @@ +# rtpair.pas +originally from [https://github.com/Postrediori/Pascal-Raytracer](https://github.com/Postrediori/Pascal-Raytracer), no license specified there # Attributions for included media files * ara.pict: Tuxyso / Wikimedia Commons / CC-BY-SA-3.0 https://commons.wikimedia.org/wiki/File:Ara-Zoo-Muenster-2013.jpg diff --git a/lib/corelib.s b/lib/corelib.s new file mode 100644 index 0000000..57f35a8 --- /dev/null +++ b/lib/corelib.s @@ -0,0 +1,1501 @@ +; Copyright 2021-2024 Sebastian Lederer. See the file LICENSE.md for details + + .EQU CR 13 + .EQU LF 10 + .EQU UART_REG 2048 + .EQU IRQC_REG 2432 + + .EQU PROG_START 24576 + .EQU FP_START 24060 + .EQU RP_START 24064 +NEWLINE: + LOADC CR + LOADCP CONOUT + CALL + LOADC LF + LOADCP CONOUT + CALL + RET + +; print string of byte characters +; takes pointer to string on eval stack +PRINTLINE: + DUP ; duplicate address as arg to printchar + LOADCP _PRINTCHAR + CALL + CBRANCH.Z PRINTLINE_EXIT ; if char is zero, exit + INC 1 ; increment address + BRANCH PRINTLINE +PRINTLINE_EXIT: + DROP ; remove address from stack + RET + +; print a single character +; takes a byte pointer on eval stack +; returns character on eval stack +_PRINTCHAR: + LOADI.S1.X2Y ; load word, keep address on stack + BSEL ; select byte of a word via address + DUP ; check for null byte + CBRANCH.Z _PRINTCHAR_XT + DUP + LOADCP CONOUT + CALL +_PRINTCHAR_XT: + RET + +; print a 32-bit hexadecimal number +; takes the value on the stack +PRINTHEXW: + BROT + DUP + LOADCP _PRINTHEXB + CALL + BROT + DUP + LOADCP _PRINTHEXB + CALL + BROT + DUP + LOADCP _PRINTHEXB + CALL + BROT + LOADCP _PRINTHEXB + CALL + RET + +_PRINTHEXB: + DUP + SHR + SHR + SHR + SHR + LOADCP _PRINTNIBBLE + CALL + LOADCP _PRINTNIBBLE + CALL + RET + +_PRINTNIBBLE: + LOADC 15 ; isolate nibble + AND + LOADC 10 + CMPU.S0 GE ; nibble >= 10 ? + CBRANCH.NZ _PRINTNIBBLE_1 ; then print a-f + LOADC '0' ; else print 0-9 + BRANCH _PRINTNIBBLE_2 +_PRINTNIBBLE_1: + LOADC 55 ; 55 + 10 == 'A' +_PRINTNIBBLE_2: + ADD + LOADCP CONOUT + CALL + RET + +_MUL10: + SHL ; x * 2 + DUP + SHL 2 ; x * 8 + ADD ; x * 2 + x * 8 = x * 10 + RET + +; shift left multiple times +; parameters: value, count +; returns: shifted value +_SHLM: + DUP + CBRANCH.Z _SHLM_X ; if count is zero, exit + LOADC 8 + CMPU.S0 LT ; count is less than 8? + CBRANCH _SHLM_1 + ; if >= 8, continue here + DEC 8 ; decrement counter by 8 + SWAP ; swap counter and value + BROT ; byte rotate value + LOADCP $FFFFFF00 ; and mask the lowest 8 bits + AND ; to get a shift left by 8 + SWAP ; swap back counter and value + BRANCH _SHLM +_SHLM_1: + DEC 1 + SWAP + SHL + SWAP + BRANCH _SHLM +_SHLM_X: + DROP ; drop counter + RET + +; shift right multiple times +; parameters: value, count +; returns: shifted value +_SHRM: + DUP + CBRANCH.Z _SHRM_X ; if count is zero, exit + DEC 1 + SWAP + SHR + SWAP + BRANCH _SHRM +_SHRM_X: + DROP ; remove counter + RET + + +; --- print signed integer as decimal +; parameter: value +PRINTDEC: + DUP + LOADC 0 + CMP GE + CBRANCH PRINTDECU + LOADC '-' + LOADCP CONOUT + CALL + NOT + INC 1 ; negate value + ; fallthrough to PRINTDECU + +; print unsigned integer as decimal +; parameter: value +; local vars: +; 0: current value +; 4: pointer to digit value table +; 8: digit counter +; 12: flag for leading zeroes +PRINTDECU: + FPADJ -16 + STORE 0 + LOADCP CONVDEC_TAB + STORE 4 + LOADC 0 + STORE 12 +PRDEC_NEXTDIGIT: + LOADC 0 + STORE 8 + LOAD 4 + LOADI ; load via pointer + CBRANCH.Z PRDECU_DONE ; if digit value is 0, we are done +DIGIT_LOOP: + LOAD 4 + LOADI + LOAD 0 + CMPU GT + CBRANCH DIGIT_DONE + LOAD 0 + LOAD 4 + LOADI + SUB + STORE 0 + LOAD 8 + INC 1 + STORE 8 + BRANCH DIGIT_LOOP +DIGIT_DONE: + LOAD 8 + CBRANCH.NZ DIGIT_OUT ; if digit is not 0, print it + LOAD 12 ; is it a leading zero, ignore it + CBRANCH.Z DIGIT_NEXT +DIGIT_OUT: + LOADC 1 ; set leading zero flag + STORE 12 + LOAD 8 + LOADCP _PRINTDIGIT + CALL +DIGIT_NEXT: + LOAD 4 ; increment digit value pointer + INC 4 + STORE 4 + BRANCH PRDEC_NEXTDIGIT +PRDECU_DONE: + LOAD 0 + LOADCP _PRINTDIGIT + CALL + FPADJ 16 + RET + +_PRINTDIGIT: + LOADC '0' + ADD + LOADCP CONOUT + CALL + RET +CONVDEC_TAB: + .WORD 1000000000,100000000,10000000,1000000,100000,10000,1000,100,10,0 + +; ------ read a 8-digit hexadecimal number from the console +; stores variables on the user stack, so the FP register must be +; inizialized. +; returns two values on the eval stack: +; - return code (topmost) +; 0 - no valid number +; 1 - valid number +; 2 - valid number and enter was pressed +; - result value +_READHEX: + FPADJ -8 + LOADC 0 ; current value + STORE 0 + LOADC 8 ; max number of digits + STORE 4 ; remaining digits counter +_READHEX_1: + LOADCP CONIN + CALL + LOADC CR ; RETURN pressed? + CMP.S0 EQ + CBRANCH _READHEX_RT + DUP + LOADCP CONOUT ; echo character + CALL + LOADCP _CONVHEXDIGIT + CALL + LOADC -1 + CMP.S0 EQ ; invalid character? + CBRANCH.NZ _READHEX_XT + LOAD 0 + SHL 1 ; shift previous nibble + SHL 1 + SHL 1 + SHL 1 + OR ; combine with last digit + STORE 0 + LOAD 4 + DEC 1 + DUP + STORE 4 + CBRANCH.NZ _READHEX_1 + BRANCH _READHEX_XT1 +_READHEX_RT: ; if no digits were entered, set return code + DROP ; drop read character + LOAD 4 ;remaining digits counter + LOADC 8 + CMP NE + CBRANCH _READHEX_RT2 + LOADC 0 ; no valid input + BRANCH _READHEX_XT3 +_READHEX_RT2: + LOADC 2 ; valid input and return pressed + BRANCH _READHEX_XT3 +_READHEX_XT: + DROP + LOAD 4 + LOADC 8 + CMP EQ ; if no digits were entered + CBRANCH _READHEX_XT0 +_READHEX_XT1: + LOADC 1 ; valid input flag + BRANCH _READHEX_XT3 +_READHEX_XT0: + LOADC 0 +_READHEX_XT3: + LOAD 0 + SWAP + FPADJ 8 + RET + +; ------ convert character on the eval stack to upper case +UPCASE: + LOADC 'a' + CMP.S0 LT + CBRANCH UPCASE_XT + LOADC 'z' + CMP.S0 GT + CBRANCH UPCASE_XT + LOADC 32 + SUB +UPCASE_XT: + RET + +; ------ convert hexadecimal digit to integer +; ------ takes an ascii character as parameter on the eval stack +; ------ returns an integer value from 0-15 on the eval stack, +; ------ or -1 if the character was not a valid hexadecimal digit +_CONVHEXDIGIT: + LOADCP UPCASE + CALL + LOADC '0' + CMP.S0 LT ; character < '0'? + CBRANCH.NZ _CONVHEXDIGIT_ERR + LOADC '9' + CMP.S0 GT ; character > '9'? + CBRANCH.NZ _CONVHEXDIGIT_ISALPHA + LOADC '0' ; character is between '0' and '9', subtract '0' + SUB + BRANCH _CONVHEXDIGIT_NBL +_CONVHEXDIGIT_ISALPHA: + LOADC 'A' + CMP.S0 LT ; character < 'A'? + CBRANCH.NZ _CONVHEXDIGIT_ERR + LOADC 'F' + CMP.S0 GT ; character > 'F'? + CBRANCH.NZ _CONVHEXDIGIT_ERR + LOADC 55 ; character is between 'A' and 'F', subtract ('A' - 10) + SUB +_CONVHEXDIGIT_NBL: + RET +_CONVHEXDIGIT_ERR: + DROP ; remove character from stack + LOADC -1 ; error + RET + +; --------- output a character on serial console +; --------- takes a character (as the lsb of a word) on the eval stack +CONOUT: + LOADC UART_REG ; address of UART register + LOADI ; load status + LOADC 256 ; check bit 8 (tx_busy) + AND + CBRANCH.NZ CONOUT ; loop if bit 8 is not zero + + ; transmitter is idle now, write character + LOADC 1024 ; TX enable bit + OR + LOADC UART_REG ; I/O address + SWAP ; swap addr and value as args for STOREI + STOREI + DROP + RET + +; ---------- check if a character has been received +; returns: 1 if a character has been received, 0 otherwise +CONAVAIL: + LOADC 0 ; preliminary result + LOADC UART_REG ; address of UART register + LOADI ; load status + LOADC 512 ; check bit 9 (rx_avail) + AND + CBRANCH.Z CONAVAIL_0 ; if bit is zero, we are done + INC 1 ; add 1 to preliminary result +CONAVAIL_0: + RET + +; ---------- wait until a character is received and return it on eval stack +CONIN: + LOADC UART_REG ; address of UART register + LOADI ; load status + LOADC 512 ; check bit 9 (rx_avail) + AND + CBRANCH.Z CONIN ; loop if bit 9 is zero + LOADC UART_REG + LOADI ; read register again + LOADC 255 ; mask status bits + AND + LOADC UART_REG ; I/O address + LOADC 512 ; set bit 9 (rx_clear) + STOREI ; write register + DROP + RET + +; return absolute value +; parameters: value +; returns: abs(value) +ABS: + LOADC 0 + CMP.S0 GE + CBRANCH ABS_XT + DEC 1 ; negate + NOT +ABS_XT: + RET + +; signed multiplication +_MUL: + ; fallthrough to MULU + +; unsigned multiplication: x * y +; parameters: [x, y] +; returns: x * y +_MULU: + FPADJ -16 + STORE 0 ; x + STORE 4 ; y + LOADC 32 + STORE 8 ; bit count + LOADC 0 + STORE 12 ; result +MULU_LOOP: + LOAD 8 + CBRANCH.Z MULU_XT ; if count is zero, exit + LOAD 0 + LOADC 1 + AND.S0 ; get bit 0 + CBRANCH.Z MULU_1 ; if bit 0 is zero, next binary digit + LOAD 12 + LOAD 4 + ADD ; result = result + y + STORE 12 +MULU_1: + SHR ; x = x >> 1 + STORE 0 + LOAD 4 + SHL ; y = y << 1 + STORE 4 + LOAD 8 + DEC 1 ; count = count -1 + STORE 8 + BRANCH MULU_LOOP +MULU_XT: + LOAD 12 + FPADJ 16 + RET + +; signed integer division +; parameters: [x,y] +; result: x/y +_DIV: + FPADJ -4 + LOADC 0 + STORE 0 ; clear negate flag + DUP + LOADC 0 + CMP GE ; is y positive? + CBRANCH DIV_ISPOS + ; y is negative + NOT + INC 1 ; negate y + LOADC -1 + STORE 0 ; set negate flag +DIV_ISPOS: + SWAP ; swap x and y + DUP + LOADC 0 + CMP GE ; is x positive? + CBRANCH DIV_ISPOS2 + ; x is negative + NOT + INC 1 ; negate x + LOAD 0 + NOT ; invert negate flag + STORE 0 +DIV_ISPOS2: + SWAP ; swap back y and x + LOADCP _DIVMODU + CALL + DROP ; throw away remainder + LOAD 0 + CBRANCH.Z DIV_XT ; negate flag set? + NOT + INC 1 ; negate value +DIV_XT: + FPADJ 4 + RET + +; signed integer modulo +; the result is negative if x is negative. +; the sign of y is ignored. +; parameters: [x,y] +; returns: remainder of x/y +_MOD: + FPADJ -4 + LOADC 0 + STORE 0 ; clear negate flag + DUP + LOADC 0 + CMP GE ; is y positive? + CBRANCH MOD_ISPOS + ; y is negative + NOT + INC 1 ; negate y +MOD_ISPOS: + SWAP ; swap x and y + DUP + LOADC 0 + CMP GE ; is x positive? + CBRANCH MOD_ISPOS2 + ; x is negative + NOT + INC 1 ; negate x + LOAD 0 + NOT ; invert negate flag + STORE 0 +MOD_ISPOS2: + SWAP ; swap back y and x + LOADCP _DIVMODU + CALL + NIP ; throw away quotient + LOAD 0 + CBRANCH.Z MOD_XT ; negate flag set? + NOT + INC 1 ; negate value +MOD_XT: + + FPADJ 4 + RET + +; unsigned integer division +; parameters: [x,y] +; result: x/y +_DIVU: + LOADCP _DIVMODU ; just call DIVMODU and throw away the remainder + CALL + DROP + RET + +; unsigned integer division with remainder +; parameters: [x,y] +; result: [ quotient, remainder ] +_DIVMODU: + FPADJ -20 + STORE 0 ; y + STORE 4 ; x + LOADC 32 + STORE 8 ; bit count + LOADC 0 + STORE 12 ; tmp value + LOADC 0 + STORE 16 ; result +DIVU_LOOP: + LOAD 8 + CBRANCH.Z DIVU_END ; if count is zero, exit + LOAD 16 + SHL ; result = result << 1 + STORE 16 + LOAD 12 + SHL ; tmp << 1 + LOAD 4 + LOADCP $80000000 ; msb of x + AND + CBRANCH.Z DIVU_1 + INC 1 ; tmp[0] is 0, so +1 means tmp[0] = 1 +DIVU_1: + DUP + STORE 12 ; tmp = tmp << 1 | msb + LOAD 0 + CMPU GE ; tmp >= y? + CBRANCH.Z DIVU_2 + LOAD 16 + INC 1 ; result = result | 1 + STORE 16 + LOAD 12 + LOAD 0 + SUB + STORE 12 ; tmp = tmp - y +DIVU_2: + LOAD 4 + SHL + STORE 4 + LOAD 8 + DEC 1 + STORE 8 + BRANCH DIVU_LOOP +DIVU_END: + LOAD 16 ; result (quotient) + LOAD 12 ; remainder + FPADJ 20 + RET + + .CPOOL + +; wait approx. 1 millisecond +; +; 83.333 MHz Clock, three instructions a 4 cycles +; 83333 / 12 = 6944.4166 +; works only if executed without wait states (i.e. +; from BRAM/SRAM) +WAIT1MSEC: + LOADCP 6944 +WAIT1LOOP: + DEC 1 + DUP + CBRANCH.NZ WAIT1LOOP + DROP + RET + +; clear a memory block +; parameters: addr, length in bytes +; length must be multiple of wordsize. +; if it is not, the last (partial) word is not cleared. +_CLEARMEM: + SHR + SHR ; calculate length in words + +CLEARMEM_L: + DUP + CBRANCH.Z CLEARMEM_X ; if zero words to do, exit + SWAP ; swap counter and addr + LOADC 0 + STOREI 4 ; store with post-increment + SWAP ; swap counter and addr back + DEC 1 ; decrement counter + BRANCH CLEARMEM_L +CLEARMEM_X: + DROP + DROP + RET + +; copy a number of words from source to destination +; parameters: [ dest, source, count ] +; source and destination may not overlap + .EQU COPYWORDS_COUNT 0 + .EQU COPYWORDS_SRC 4 + .EQU COPYWORDS_DEST 8 +_COPYWORDS: + FPADJ -12 + STORE COPYWORDS_COUNT ; store args to local vars + STORE COPYWORDS_SRC + STORE COPYWORDS_DEST + LOAD COPYWORDS_COUNT ; we will keep count on the stack inside the loop +COPYWORDS_L0: + DUP ; count is on tos, duplicate it + CBRANCH.Z COPYWORDS_XT ; check if count is zero + DEC 1 ; if not, decrement + LOAD COPYWORDS_DEST ; load dest addr for STOREI below + LOAD COPYWORDS_SRC ; load src addr + INC.S1.X2Y 4 ; increment by 4 and put as new value on tos + STORE COPYWORDS_SRC ; store again, old addr is now on tos + LOADI ; load value by old addr + STOREI 4 ; store value and post-increment + STORE COPYWORDS_DEST ; store post-incremented addr + BRANCH COPYWORDS_L0 +COPYWORDS_XT: + DROP ; drop count value + FPADJ 12 + RET + +; compare a number of words +; parameters: [ dest, source, count ] +; returns: 1 if all words are equal, 0 otherwise + .EQU CMPWORDS_COUNT 0 + .EQU CMPWORDS_SRC 4 + .EQU CMPWORDS_DEST 8 +_CMPWORDS: + FPADJ -12 + STORE CMPWORDS_COUNT ; store args to local vars + STORE CMPWORDS_SRC + STORE CMPWORDS_DEST + LOAD CMPWORDS_COUNT +CMPWORDS_L0: + DUP ; count is on tos, duplicate it + CBRANCH.Z CMPWORDS_XT ; check if count is zero + DEC 1 ; if not, decrement + LOAD CMPWORDS_SRC ; load src addr + INC.S1.X2Y 4 ; increment by 4 and put as new value on tos + STORE CMPWORDS_SRC ; store again, old addr is now on tos + LOADI ; load src value + LOAD CMPWORDS_DEST ; load dest addr + INC.S1.X2Y 4 ; increment by 4 and put as new value on tos + STORE CMPWORDS_DEST ; store again, old addr is now on tos + LOADI ; load dest value + CMPU EQ + CBRANCH CMPWORDS_L0 ; if words are equal, continue loop + DROP ; drop count value + LOADC 0 ; load exit code 0 + BRANCH CMPWORDS_XT2 +CMPWORDS_XT: + DROP ; drop count value + LOADC 1 ; load exit code 1 +CMPWORDS_XT2: + FPADJ 12 + RET + + .CPOOL +; --------- Graphics Library --------------- + ; vga controller registers + .EQU FB_RA $900 + .EQU FB_WA $901 + .EQU FB_IO $902 + .EQU FB_PS $903 + .EQU FB_PD $904 + .EQU FB_CTL $905 +; set a pixel in fb memory +; parameters: x,y - coordinates +PUTPIXEL_1BPP: + ; calculate vmem address: + OVER ; duplicate x + ; divide x by 32 + SHR + SHR + SHR + SHR + SHR + SWAP + ; multiply y by words per line + SHL 2 + SHL 2 + SHL + + ADD ; add results together for vmem addr + + DUP + LOADCP FB_WA + SWAP + STOREI ; store to framebuffer write addr register + DROP + LOADCP FB_RA ; and to framebuffer read addr register + SWAP + STOREI + DROP + + ; x is now at top of stack + ; get bit value from x modulo 32 + LOADC 31 + AND + SHL 2 ; (x & 31) * 4 = offset into table + LOADCP INT_TO_PIX_TABLE + ADD + LOADI + + LOADCP FB_IO + ; read old vmem value + LOADCP FB_IO + LOADI + ; or in new bit + OR + ; write new value + STOREI + DROP + + RET + +INT_TO_PIX_TABLE: + .WORD %10000000_00000000_00000000_00000000 + .WORD %01000000_00000000_00000000_00000000 + .WORD %00100000_00000000_00000000_00000000 + .WORD %00010000_00000000_00000000_00000000 + .WORD %00001000_00000000_00000000_00000000 + .WORD %00000100_00000000_00000000_00000000 + .WORD %00000010_00000000_00000000_00000000 + .WORD %00000001_00000000_00000000_00000000 + .WORD %00000000_10000000_00000000_00000000 + .WORD %00000000_01000000_00000000_00000000 + .WORD %00000000_00100000_00000000_00000000 + .WORD %00000000_00010000_00000000_00000000 + .WORD %00000000_00001000_00000000_00000000 + .WORD %00000000_00000100_00000000_00000000 + .WORD %00000000_00000010_00000000_00000000 + .WORD %00000000_00000001_00000000_00000000 + .WORD %00000000_00000000_10000000_00000000 + .WORD %00000000_00000000_01000000_00000000 + .WORD %00000000_00000000_00100000_00000000 + .WORD %00000000_00000000_00010000_00000000 + .WORD %00000000_00000000_00001000_00000000 + .WORD %00000000_00000000_00000100_00000000 + .WORD %00000000_00000000_00000010_00000000 + .WORD %00000000_00000000_00000001_00000000 + .WORD %00000000_00000000_00000000_10000000 + .WORD %00000000_00000000_00000000_01000000 + .WORD %00000000_00000000_00000000_00100000 + .WORD %00000000_00000000_00000000_00010000 + .WORD %00000000_00000000_00000000_00001000 + .WORD %00000000_00000000_00000000_00000100 + .WORD %00000000_00000000_00000000_00000010 + .WORD %00000000_00000000_00000000_00000001 + +PUTMPIXEL: + LOADC 1 +; set a pixel in fb memory +; parameters: x,y,color - coordinates, color value (0-15) +PUTPIXEL: +PUTPIXEL_4BPP: + .EQU PUTPIXEL_X 0 + .EQU PUTPIXEL_Y 4 + .EQU PUTPIXEL_COLOR 8 + .EQU PUTPIXEL_PIXPOS 12 + .EQU PUTPIXEL_FS 16 + + FPADJ -PUTPIXEL_FS + + STORE PUTPIXEL_COLOR + STORE PUTPIXEL_Y + STORE PUTPIXEL_X + + + ; calculate vmem address: (x / 8) + (y * 80) + LOAD PUTPIXEL_X + ; divide x by 8 + SHR + SHR + SHR + + LOAD PUTPIXEL_Y + ; multiply y by words per line + SHL 2 + SHL 2 ; * 16 + DUP + SHL 2; * 64 + ADD ; x*16 + x*64 + + ADD ; add results together for vmem addr + + LOADCP FB_WA + OVER + STOREI ; store to framebuffer write addr register + DROP + LOADCP FB_RA ; and to framebuffer read addr register + SWAP ; swap addr and value for STOREI + STOREI + DROP + + LOAD PUTPIXEL_X + ; |0000.0000|0000.0000|0000.0000|0000.1111| + LOADC 7 + AND ; calculate pixel position in word + LOADC 7 + SWAP + SUB ; pixpos = 7 - (x & 7) + STORE PUTPIXEL_PIXPOS + + LOAD PUTPIXEL_COLOR + LOAD PUTPIXEL_PIXPOS + SHR ; rcount = pixpos / 2 +ROTLOOP_: + DUP ; exit loop if rcount is 0 + CBRANCH.Z ROTLOOP_END + SWAP ; pixel value is now on top of stack + BROT ; value = value << 8 + SWAP ; rcount is now on top of stack + DEC 1 ; rcount = rcount - 1 + BRANCH ROTLOOP_ +ROTLOOP_END: + DROP ; drop rcount + ; shifted pixel value is now at top of stack + LOAD PUTPIXEL_PIXPOS + LOADC 1 + AND + CBRANCH.Z EVEN_PIXPOS + SHL 2 ; if pixpos is odd, shift by 4 bits + SHL 2 +EVEN_PIXPOS: + LOAD PUTPIXEL_X + ; get bit value from x modulo 8 + LOADC 7 + AND + SHL 2 ; (x & 7) * 4 = offset into table + LOADCP INT_TO_MASK_TABLE + ADD + LOADI + + ; read old vmem value + LOADCP FB_IO + LOADI + ; mask bits + AND + ; or in shifted pixel value + OR + + ; write new value + LOADCP FB_IO + SWAP + STOREI + DROP + + FPADJ PUTPIXEL_FS + RET + + .CPOOL + +INT_TO_MASK_TABLE: + .WORD %00001111_11111111_11111111_11111111 + .WORD %11110000_11111111_11111111_11111111 + .WORD %11111111_00001111_11111111_11111111 + .WORD %11111111_11110000_11111111_11111111 + .WORD %11111111_11111111_00001111_11111111 + .WORD %11111111_11111111_11110000_11111111 + .WORD %11111111_11111111_11111111_00001111 + .WORD %11111111_11111111_11111111_11110000 + +; draw a line between two points +; parameters: x0, y0, x1, y1, color + .EQU DL_X0 0 + .EQU DL_Y0 4 + .EQU DL_X1 8 + .EQU DL_Y1 12 + .EQU DL_DX 16 + .EQU DL_DY 20 + .EQU DL_ERR 24 + .EQU DL_E2 28 + .EQU DL_SX 32 + .EQU DL_SY 36 + .EQU DL_COL 40 + .EQU STACKFRAME_SIZE 44 + +DRAWLINE_M: + LOADC 1 +DRAWLINE: + FPADJ -STACKFRAME_SIZE + + STORE DL_COL ; store args + STORE DL_Y1 + STORE DL_X1 + STORE DL_Y0 + STORE DL_X0 + + LOAD DL_X1 ; dx = abs(x1-x0) + LOAD DL_X0 + SUB + LOADCP ABS + CALL + STORE DL_DX + + LOAD DL_Y1 ; dy = -abs(y1-y0) + LOAD DL_Y0 + SUB + LOADCP ABS + CALL + DEC 1 + NOT + STORE DL_DY + + LOAD DL_X0 ; sx = (x0 dy + LOAD DL_DY + CMP GT + CBRANCH.Z DL_SKIP1 + + LOAD DL_ERR ; err += dy + LOAD DL_DY + ADD + STORE DL_ERR + + LOAD DL_X0 ; x0 += sx + LOAD DL_SX + ADD + STORE DL_X0 + +DL_SKIP1: + LOAD DL_E2 ; if e2 < dx + LOAD DL_DX + CMP LT + CBRANCH.Z DL_SKIP2 + + LOAD DL_ERR ; err += dx + LOAD DL_DX + ADD + STORE DL_ERR + + LOAD DL_Y0 ; y0 += sy + LOAD DL_SY + ADD + STORE DL_Y0 + +DL_SKIP2: + BRANCH DL_LOOP +DL_END: + FPADJ STACKFRAME_SIZE + RET + +; initialize the palette registers +INITPALETTE: + LOADCP DEFAULT_PALETTE ; load pointer to color table + LOADC 0 ; load counter +INITPAL_0: + DUP + LOADC FB_PS ; store counter to palette select register + SWAP ; swap addr and value for STOREI + STOREI + DROP + + SWAP ; pointer on top of stack + DUP + LOADI ; load color value + LOADC FB_PD + SWAP ; swap addr and value for STOREI + STOREI ; store to palette data register + DROP + INC 4 ; increment pointer + + SWAP ; counter on top of stack + DUP + LOADC 15 + CMPU EQ + CBRANCH INITPAL_X ; exit if counter is 15 + + INC 1 ; increment counter + BRANCH INITPAL_0 + +INITPAL_X: + DROP ; remove counter and pointer + DROP + RET + +; set a palette register +; parameters [ palette slot nr, color value ] +SETPALETTE: + SWAP ; slot nr to top + LOADC FB_PS ; load address of palette select register + SWAP ; swap addr and slot nr for STOREI + STOREI + DROP ; remove addr from STOREI + ; left on stack now: color value + LOADC FB_PD ; load address of palette data register + SWAP ; swap addr and color value for STOREI + STOREI + DROP ; remove addr + + RET + +DEFAULT_PALETTE: + .WORD 0, $FFF, $F00, $0F0, $00F, $0FF, $F0F, $FF0 + .WORD $777, $777, $700, $070, $007, $077, $707, $770 + +; set whole video memory to zero +CLEARGRAPHICS: + LOADC 0 +CL_LOOP: + LOADC FB_WA + OVER ; duplicate value + STOREI + DROP + + LOADC FB_IO + LOADC 0 + STOREI + DROP + + INC 1 + + LOADCP 32768 + CMP.S0 NE + CBRANCH CL_LOOP + + DROP + + RET + +INITGRAPHICS: + LOADCP CLEARGRAPHICS + CALL + LOADCP INITPALETTE + CALL + RET + +; wait for vertical blank +; we first wait for the VBLANK bit +; to become zero to make sure we +; catch the beginning of the vertical blank +WAITVSYNC: + ; wait for VBLANK to become zero + LOADC FB_CTL + LOADI ; read control register + LOADC 1 ; check bit 0 (VBLANK) + AND + CBRANCH.NZ WAITVSYNC ; if set, loop +VSYNC_WAIT1: + ; wait for VBLANK to become one + LOADC FB_CTL + LOADI ; read control register + LOADC 1 ; check bit 0 (VBLANK) + AND + CBRANCH.Z VSYNC_WAIT1 ; if not set, loop + RET + +; args: number of bytes, pointer to buf, +HEXDUMP: + DUP + LOADI + LOADCP PRINTHEXW + CALL + LOADC ' ' + LOADCP CONOUT + CALL + INC 4 + + DUP + LOADI + LOADCP PRINTHEXW + CALL + LOADC ' ' + LOADCP CONOUT + CALL + INC 4 + + DUP + LOADI + LOADCP PRINTHEXW + CALL + LOADC ' ' + LOADCP CONOUT + CALL + INC 4 + + DUP + LOADI + LOADCP PRINTHEXW + CALL + LOADC ' ' + LOADCP CONOUT + CALL + INC 4 + + LOADCP NEWLINE + CALL + + SWAP ; swap pointer and counter + LOADC 16 + SUB + DUP + CBRANCH.Z HEXDUMP_END ; end if counter is zero + SWAP ; swap back counter and pointer + BRANCH HEXDUMP + +HEXDUMP_END: + DROP + DROP + RET + +; inquire cursor position +; args: pointer to columns variable, pointer to rows variable +GETCURSORPOS: + LOADCP TERM_CPR_STR + LOADCP PRINTLINE + CALL + + LOADCP CONIN ; skip ESC + CALL + DROP + LOADCP CONIN ; and '[' + CALL + DROP + + LOADC ';' + LOADCP _TERMRCVINT + CALL + STOREI + DROP + + LOADC 'R' + LOADCP _TERMRCVINT + CALL + STOREI + DROP + + RET + +; receive digits and compose an integer value +; up to a termination character or an ';' +; args: termination character +; returns: -1 on error (invalid digit) + +_TERMRCVINT: + FPADJ -4 + STORE 0 + + LOADC 0 ; start with 0 value +RCVINT_L: + LOADCP CONIN + CALL + + DUP ; duplicate received char + LOAD 0 ; compare with terminator + CMP EQ ; if equal, + CBRANCH RCVINT_XT ; exit + + LOADC '0' ; subtract ascii value to get + SUB ; numerical value + + DUP + LOADC 0 ; check if less than zero + CMP LT + CBRANCH RCVINT_ERR ; if yes, error + + DUP + LOADC 9 + CMP GT ; check if > 9 + CBRANCH RCVINT_ERR ; if yes, error + + SWAP + LOADCP _MUL10 ; old value * 10 (shift digits to the left) + CALL + + ADD ; add to value + BRANCH RCVINT_L ; next digit +RCVINT_ERR: + DROP + DROP + LOADC -1 + BRANCH RCVINT_XT2 +RCVINT_XT: + DROP +RCVINT_XT2: + FPADJ 4 + RET + +TERM_CPR_STR: .BYTE 27, "[6n", 0 ; ANSI Cursor Position Report + + .CPOOL + +GETTICKS: + LOADC IRQC_REG + LOADI + LOADC -256 + AND + BROT + BROT + BROT + RET + + .EQU CRLD_BLOCK 0 + .EQU CRLD_BYTES 4 + .EQU CRLD_ADDR 8 + .EQU CRLD_FS 12 + +; load a program image from sd card +; args: device id, block no, size in bytes +CORELOAD: + ; We need to set the FP and RP registers, + ; because we might overwrite that + ; memory area where the calling program + ; has its user and return stack + + LOADCP FP_START + STOREREG FP + LOADCP RP_START + STOREREG RP + + FPADJ -CRLD_FS + STORE CRLD_BYTES + STORE CRLD_BLOCK + DROP ; ignore device ID, + ; we support only one sd card + + ; divide bytes by 512 and add one + ; to get block count + LOAD CRLD_BYTES + LOADC 9 + LOADCP _SHRM + CALL + INC 1 + ; keep block count on stack + + ; start at address 24576 + LOADCP PROG_START + STORE CRLD_ADDR + +CRLD_LP: + ; read a block + LOAD CRLD_BLOCK + LOADCP CARDREADBLK + CALL + DROP ; ignore error for now + + LOAD CRLD_ADDR + LOADCP CARD_BUF + LOADC 128 + LOADCP _COPYWORDS + CALL + + ; advance dest pointer + LOAD CRLD_ADDR + LOADC 512 + ADD + STORE CRLD_ADDR + + ; increment block number + LOAD CRLD_BLOCK + INC 1 + STORE CRLD_BLOCK + + ; decrement block count on stack + DEC 1 + DUP + CBRANCH.NZ CRLD_LP ; if block count not zero, loop + DROP ; remove block count +CRLD_CLEAN: + ; clean up partial block + LOADC 512 + LOAD CRLD_BYTES + INC 3 ; round up to next word + LOADC -4 + AND + LOADC 511 ; get remainder by 512 + AND + SUB ; subtract to get number of remaining bytes + ; in last block + + LOAD CRLD_ADDR ; this is now the addr of the last + ; byte in the last block + 1 + OVER ; duplicate number of remaining bytes + SUB ; and subtract from addr + + SWAP ; swap addr and number of remaining bytes + LOADCP _CLEARMEM + CALL + + ; clear estack + + ; release our stack frame + FPADJ CRLD_FS + + ; jump to program start address + LOADCP PROG_START + JUMP + + ; no RET + + .CPOOL + +READDIRBLK: +; parameters: [ blkno, ptr to DirBlock, ptr to error return value, device id ] +; same routine as READBLOCK, is referenced by two names to convert buffer types + +; parameters: [ blkno, ptr to PartitionTableBlock, ptr to error return value, device id ] +READPARTBLK: +; same routine as READBLOCK, is referenced by two names to convert buffer types + +READBLOCK: +; parameters: [ blkno, ptr to IOBlock, ptr to error return value, device id ] + DROP ; ignore device id + + LOADC 0 + STOREI ; set return value to zero + DROP + SWAP ; swap blkno and ptr + LOADCP CARDREADBLK ; read that block number + CALL + DROP ; ignore error for now + ; TODO: store it via error ptr + ; ptr to PartitionTableBlock is now on ToS + LOADCP CARD_BUF + LOADC 128 + LOADCP _COPYWORDS ; copy block to destination buffer + CALL + + RET + +WRITEPARTBLK: +WRITEDIRBLK: +; parameters: [ blkno, ptr to IOBlock, ptr to error return value, device id ] +WRITEBLOCK: + DROP ; ignore device id + + LOADC 0 + STOREI ; set return value to zero + DROP + + LOADCP CARD_BUF + SWAP + LOADC 128 + LOADCP _COPYWORDS ; copy block to card_buf + CALL + + LOADCP CARDWRITEBLK ; write that block number + CALL + DROP ; ignore error for now + ; TODO: store it via error ptr + ; ptr to PartitionTableBlock is now on ToS + RET + +%include "sdcardlib.s" + + .CPOOL + +SHELLWORKFILE: .WORD 0,68 + .BLOCK 17 +SHELLCMD: .WORD 0,40 + .BLOCK 8 +SHELLARG: .WORD 0 +PARGCOUNT: .WORD 0 +PARGS: .WORD 0,80 + .BLOCK 20 + .WORD 0,80 + .BLOCK 20 + .WORD 0,80 + .BLOCK 20 + .WORD 0,80 + .BLOCK 20 + .WORD 0,80 + .BLOCK 20 + .WORD 0,80 + .BLOCK 20 + .WORD 0,80 + .BLOCK 20 + .WORD 0,80 + .BLOCK 20 + +DEFAULTVOLUME: .WORD 0,32 + .BLOCK 8 + +SYSCLOCK: + .BLOCK 6 +SYSBOOTTICKS: + .WORD 0 +SYSLASTTICKS: + .WORD 0 + +; copy words to screen memory +; args: pointer to 32000 words of pixel data +PUTSCREEN: + LOADC FB_WA + LOADC 0 ; initialize write address register + STOREI + DROP + + LOADCP 32000 ; word count +PUTSCREEN_L0: + SWAP ; [ count, addr ] + DUP + LOADI ; load pixel word + LOADC FB_IO + SWAP ; swap addr and value for STOREI + STOREI ; store to vmem io register + DROP + + INC 4 ; next word + + SWAP ; swap addr and count + DEC 1 ; decrement count + + DUP + CBRANCH.NZ PUTSCREEN_L0 ; loop if count is not zero + + DROP ; remove counter and addr + DROP + + RET + + +%export _MUL +%export _MULU +%export _DIV +%export _DIVU +%export _MOD +%export _DIVMODU +%export _SHRM +%export _SHLM +%export _COPYWORDS +%export _CMPWORDS +%export _CLEARMEM diff --git a/lib/coreloader.s b/lib/coreloader.s new file mode 100644 index 0000000..542b667 --- /dev/null +++ b/lib/coreloader.s @@ -0,0 +1,279 @@ +; Copyright 2021-2024 Sebastian Lederer. See the file LICENSE.md for details + .ORG 4096 + +CORELOADER: + ; initialize program stack and + ; return stack pointers + LOADCP 24060 + STOREREG FP + LOADCP 24064 + STOREREG RP + + LOADCP SYSBOOTTICKS + LOADCP GETTICKS + CALL + STOREI + DROP + + LOADCP INITSDCARD + CALL + + ;LOADCP FIND_SYSPART ; no need to call, it never + ;CALL ; returns, so just fall through + + .EQU PART_START 0 + .EQU EXTENT_SIZE 4 + .EQU DIR_SIZE 8 + .EQU SLOT_NO 12 + .EQU SIZE_BYTES 16 + .EQU PRG_START_BLK 20 + .EQU FIND_FS 24 + + .EQU PARTENTRY_SIZE 64 + .EQU DIRENTRY_SIZE 64 +FIND_SYSPART: + FPADJ -FIND_FS + ; load block 0 + LOADC 0 + LOADCP CARDREADBLK + CALL + + DUP ; non-zero return code means error + CBRANCH.Z FIND_1 + + LOADCP PRINTHEXW + CALL + LOADCP NEWLINE + CALL + LOADC 0 + JUMP + +FIND_1: + DROP ; remove return code + + ;LOADC 512 + ;LOADCP CARD_BUF + ;LOADCP HEXDUMP + ;CALL + + ; address of the first partition entry + LOADCP CARD_BUF +FIND_L: + DUP ; dup addr for comparison + LOADCP SYSPART_NAME + LOADC SYSNAME_WORDS + LOADCP _CMPWORDS + CALL + CBRANCH.NZ FIND_FOUND + ; go to next entry + LOADC PARTENTRY_SIZE + ADD + + ; check if address is still + ; within the data block + DUP + LOADCP CARD_BUF,512 + CMP LT + CBRANCH FIND_L + + ; remove address + DROP + + ; not found, complain and + ; go back to ROM monitor + LOADCP SYSPART_ERR + LOADCP PRINTLINE + CALL + + LOADC 0 + JUMP + +FIND_FOUND: + ; address of the part entry is on stack + + ; check if partition is enabled + DUP ; duplicate address + LOADC 40 ; add PartFlags field offset + ADD + LOADI + LOADC 1 + AND ; check bit 0 (PartEnabled) + CBRANCH.Z FIND_L ; if not set, continue loop + + + ; address of part entry is still on stack + DUP + LOADC 44 ; add startBlock field offset + ADD + LOADI ; get start block number + STORE PART_START + + ; address of part entry is still on stack + DUP + LOADC 52 ; move to extentSize field + ADD + LOADI ; get value + STORE EXTENT_SIZE + + ; address of part entry is still on stack + LOADC 56 ; move to dirSize field + ADD + LOADI ; get value + STORE DIR_SIZE + + LOADC 0 + STORE SLOT_NO ; start with dirslot 0 + + LOAD PART_START ; start with first block of the partition +FIND_FILE: + DUP ; duplicate block number + LOADCP CARDREADBLK ; read that block + CALL + DROP ; ignore error + + ; scan directory entries for shell file name + LOADCP CARD_BUF +FIND_FILE_L: + DUP + LOADCP SHELL_NAME + LOADC SHELLNAME_WORDS + LOADCP _CMPWORDS ; compare names + CALL + CBRANCH.NZ FIND_F_FOUND ; exit loop if names match + + ; check if current dirslot no + ; is below maximum number of slots + LOAD SLOT_NO + LOAD DIR_SIZE + CMP GE + CBRANCH FIND_F_NOTFOUND ; max slots reached, exit + + ; add 1 to SLOT_NO + LOAD SLOT_NO + INC 1 + STORE SLOT_NO + + ; address is still on stack + LOADC DIRENTRY_SIZE + ADD ; go to next dir entry + + ; check if address is still + ; below end of data block + DUP + LOADCP CARD_BUF,512 + CMP LT + CBRANCH FIND_FILE_L ; if it is below, loop + + DROP ; remove dir entry addr + + ; block no is still on stack + INC 1 + BRANCH FIND_FILE ; read next block + +FIND_F_NOTFOUND: + LOADCP SHELL_ERR + LOADCP PRINTLINE + CALL + + ; remove entry addr and block number + DROP + DROP + LOADC 0 + JUMP + +FIND_F_FOUND: + ; found the file name, now check if it has the right flags + + ; address of dir entry is still on stack + DUP + LOADC 40 ; add flags field offset + ADD + LOADI ; load flags + LOADC 16 ; test for SlotFirst flag + AND + CBRANCH.Z FIND_FILE_L ; if not set, continue loop + + ;LOADCP FOUND_MSG + ;LOADCP PRINTLINE + ;CALL + + ; we got the right file, now calculate start block + ; and get file size from dir entry + + ; address of dir entry is still on stack + ; phys start block = part start + slot_no * (extent_size/512) + LOAD EXTENT_SIZE + LOADC 9 + LOADCP _SHRM + CALL + LOAD SLOT_NO + LOADCP _MUL + CALL + LOAD PART_START + ADD + + ;DUP + ;LOADCP PRINTHEXW + ;CALL + ;LOADC ' ' + ;LOADCP CONOUT + ;CALL + + STORE PRG_START_BLK + + ; address of dir entry is still on stack + LOADC 44 + ADD ; add sizeBytes field offset + LOADI ; get size in bytes + + ;DUP + ;LOADCP PRINTHEXW + ;CALL + ;LOADCP NEWLINE + ;CALL + + STORE SIZE_BYTES + + ; remove block number + DROP + + ; set argument count to 0 + ; in case this gets called + ; by a terminating program + LOADCP PARGCOUNT + LOADC 0 + STOREI + DROP + + LOADC 0 ; device id is always 0 + LOAD PRG_START_BLK + LOAD SIZE_BYTES + ; release our stack frame + FPADJ FIND_FS + + ; load program + LOADCP CORELOAD + CALL + + LOADC 0 + JUMP + + .CPOOL + + .EQU SYSNAME_WORDS 4 +SYSPART_NAME: + .WORD 6, 32 + .BYTE "SYSTEM" +SYSPART_ERR: + .BYTE "No ""SYSTEM"" partition.",13,10,10,0 + .EQU SHELLNAME_WORDS 5 +SHELL_NAME: + .WORD 10,32 + .BYTE "shell.prog" +SHELL_ERR: + .BYTE "No shell on ""SYSTEM"" partition.",13,10,10,0 + +FOUND_MSG: + .BYTE " shell.prog ",0 + +%include corelib.s diff --git a/lib/float32.s b/lib/float32.s new file mode 100644 index 0000000..4b0ad9c --- /dev/null +++ b/lib/float32.s @@ -0,0 +1,1053 @@ +; Copyright 2021-2024 Sebastian Lederer. See the file LICENSE.md for details + +; FLOAT32 format: +;| 31 | 30-8 | 7-0 | +;|sign| fraction | exp | + +; exp has a bias of 128 +; sign = 1: negative number + + .EQU FLOAT32_EXPMASK %00000000000000000000000011111111 + .EQU FLOAT32_FRCMASK %01111111111111111111111100000000 + .EQU FLOAT32_SGNMASK %10000000000000000000000000000000 + .EQU FLOAT32_FRCMSBM %01000000000000000000000000000000 + .EQU FLOAT32_OVRFLOW %10000000000000000000000000000000 + .EQU FLOAT32_RNDMASK %00000000000000000000000010000000 + .EQU FLOAT32_RNDINCR %00000000000000000000000100000000 + .EQU FLOAT32_FRCLSB %00000000000000000000000100000000 + + .EQU FLOAT32_MAX_EXP 255 + .EQU FLOAT32_BIAS 127 + .EQU FLOAT32_FRCBITS 23 + .EQU FLOAT32_EXP_BITS 8 + +; unpack a float32 value into +; three fields: exponent, fraction, sign +; ptr is a pointer to an array with the three fields +; the sign flag is 0 or 1. + +; parameters: [ floatval, ptr ] +_UNPACKFLOAT32: + OVER ; [ float, ptr, float ] + LOADC FLOAT32_EXPMASK ; [ float, ptr, float, mask ] + AND ; [ float, ptr, exp ] + STOREI 4 ; [ float, ptr + 4 ] + OVER ; [ float, ptr + 4, float ] + LOADCP FLOAT32_FRCMASK ; [ float, ptr + 4 , float, mask ] + AND ; [ float, ptr + 4 , frac ] + STOREI 4 ; [ float, ptr + 8 ] + SWAP ; [ ptr + 8, float ] + LOADCP FLOAT32_SGNMASK ; [ ptr + 8, float, mask ] + AND ; [ ptr + 8, signbit ] + LOADC 0 ; [ ptr + 8, signbit, 0 ] + CMPU NE ; [ ptr + 8, sign ] + STOREI ; [ ptr + 8 ] + DROP ; [] + RET + +; pack exponent, fraction, sign into a single 32-bit value +; ptr is a pointer to an array with the three fields +; parameters: [ ptr ] +; returns: float value +_PACKFLOAT32: + LOADI.S1.X2Y ; [ ptr, exp ] + OVER ; [ ptr, exp, ptr ] + INC 4 ; [ ptr, exp, ptr + 4 ] + LOADI ; [ ptr, exp, frac ] + LOADCP FLOAT32_FRCMASK ; [ ptr, exp, frac, mask ] + AND ; [ ptr, exp, frac ] + OR ; [ ptr, exp|frac ] + OVER ; [ ptr, exp|frac, ptr ] + INC 8 ; [ ptr, exp|frac, ptr + 8] + LOADI ; [ ptr, exp|frac, signflag ] + CBRANCH.Z PACKFL_1 ; [ ptr, exp | frac ] + LOADCP FLOAT32_SGNMASK ; [ ptr, exp|frac, signmask ] + ADD ; [ ptr, floatval ] +PACKFL_1: + SWAP ; [ floatval, ptr ] + DROP ; [ floatval ] + RET + +; adds to floating point values a and b +; parameters: [ a, b ] +; returns: sum of a and b + .EQU FL_E_A 0 + .EQU FL_F_A 4 + .EQU FL_S_A 8 + .EQU FL_E_B 12 + .EQU FL_F_B 16 + .EQU FL_S_B 20 + .EQU FL_E_R 24 + .EQU FL_F_R 28 + .EQU FL_S_R 32 + .EQU ADDFL_SUB 36 + .EQU ADDFL_FS 40 + +_ADDFLOAT32: + FPADJ -ADDFL_FS + ; unpack b into e_b and f_b + LOADREG FP + LOADC FL_E_B + ADD ; addr of FL_E_B + LOADCP _UNPACKFLOAT32 + CALL + ; unpack a into e_a and f_a + LOADREG FP ; addr of FL_E_A + LOADCP _UNPACKFLOAT32 + CALL + + + ; if abs(a) < abs(b), swap a and b (this includes e_a < e_b) + LOAD FL_E_A + LOAD FL_E_B + CMPU GT + CBRANCH ADDFL_1 ; don't swap if e_a > e_b + ; e_a <= e_b + ; check if e_a < e_b + LOAD FL_E_A + LOAD FL_E_B + CMPU LT + CBRANCH ADDFL_1_1 ; swap if e_a < e_b + ; e_a = e_b + ; check fractions + LOAD FL_F_A + LOAD FL_F_B + CMPU GE + CBRANCH ADDFL_1 ; dont't swap if f_a >= f_b + +ADDFL_1_1: + ;LOADC '"' + ;LOADCP CONOUT + ;CALL + + LOAD FL_E_A + LOAD FL_E_B + STORE FL_E_A + STORE FL_E_B + LOAD FL_F_A + LOAD FL_F_B + STORE FL_F_A + STORE FL_F_B + LOAD FL_S_A + LOAD FL_S_B + STORE FL_S_A + STORE FL_S_B +ADDFL_1: + ; e_r := e_a, result exp is exp from a + LOAD FL_E_A + STORE FL_E_R + + LOAD FL_S_A ; take result sign from a (which might be swapped with b here) + STORE FL_S_R + + LOAD FL_S_A ; check if the signs of a and b differ + LOAD FL_S_B + XOR ; if the xor of both sign flags is 1, signs are not the same + STORE ADDFL_SUB ; then we do a subtraction later + + ; ? if (e_a - e_b) > precision +1: + ; ? set f_r to f_a + + ; shift right f_b by (e_a - e_b) bits + LOAD FL_E_A + LOAD FL_E_B + SUB + + ;LOADCP NEWLINE + ;CALL + ;LOADC 'e' + ;LOADCP CONOUT + ;CALL + ;DUP + ;LOADCP PRINTDEC + ;CALL + ;LOADCP NEWLINE + ;CALL + + LOAD FL_F_B ; on stack now: [ counter, f_b ] +ADDFL_L1: + OVER ; check counter for zero + CBRANCH.Z ADDFL_2 ; if yes, loop is done + SHR ; shift right + SWAP ; swap counter and value + DEC 1 ; decrement counter + SWAP ; swap back + BRANCH ADDFL_L1 ; next +ADDFL_2: + STORE FL_F_B ; store result + DROP ; remove counter + + ;LOADC 'a' + ;LOADCP CONOUT + ;CALL + ;LOAD FL_F_A + ;LOADCP PRINTHEXW + ;CALL + ;LOADCP NEWLINE + ;CALL + ;LOADC 'b' + ;LOADCP CONOUT + ;CALL + ;LOAD FL_F_B + ;LOADCP PRINTHEXW + ;CALL + ;LOADCP NEWLINE + ;CALL + + ; set f_r to f_a + f_b + ; (or f_r = f_a - f_b if we have a negative sign somewhere) + LOAD FL_F_A + LOAD FL_F_B + LOAD ADDFL_SUB ; do we need a subtract? + CBRANCH ADDFL_2_1 ; yes, skip add instruction + ADD ; no, do add and skip sub instruction + BRANCH ADDFL_2_2 +ADDFL_2_1: + ;LOADC '-' + ;LOADCP CONOUT + ;CALL + ;LOADCP NEWLINE + ;CALL + + SUB +ADDFL_2_2: + ;DUP + ;LOADCP PRINTHEXW + ;CALL + ;LOADCP NEWLINE + ;CALL + + ; normalize: + ; if overflow bit of f_r is set, scale right + DUP + LOADCP FLOAT32_OVRFLOW ; isolate overflow bit + AND + + CBRANCH.Z ADDFL_3 + + ;LOADC 'V' + ;LOADCP CONOUT + ;CALL + + ; scale right: shift right f_r by one, increment e_r by one + SHR + LOAD FL_E_R + INC 1 + STORE FL_E_R +ADDFL_3: + ; check if result is zero + DUP + CBRANCH.NZ ADDFL_3_1 + ; set exponent to something useful + LOADC 0 + STORE FL_E_R + ; clear sign, we don't want -0 + LOADC 0 + STORE FL_S_R + + BRANCH ADDFL_4 + +ADDFL_3_1: + ; if bit 30 of f_r is zero, scale left + DUP + LOADCP FLOAT32_FRCMSBM ; isolate msb of fraction + AND + CBRANCH.NZ ADDFL_4 + + ;LOADC '<' + ;LOADCP CONOUT + ;CALL + ;LOADCP NEWLINE + ;CALL + + ; scale left and repeat previous step + SHL ; shift fraction + LOAD FL_E_R ; decrement exponent + DEC 1 + STORE FL_E_R + BRANCH ADDFL_3 ; repeat +ADDFL_4: + ; round: + ; simple round algorithm: if the bit below + ; the least significat bit is 1, round up + ; and check the overflow bit again + + DUP + LOADC FLOAT32_RNDMASK ; test rounding bit + AND + CBRANCH.Z ADDFL_5 ; if not set, skip rounding + + ;LOADC '~' + ;LOADCP CONOUT + ;CALL + ;LOADCP NEWLINE + ;CALL + + LOADC FLOAT32_RNDINCR + ADD + + LOADCP FLOAT32_FRCMASK ; remove rounded off bits + AND + + BRANCH ADDFL_3_1 ; check for overflow again +ADDFL_5: + + STORE FL_F_R + + ;LOADCP NEWLINE + ;CALL + ;LOADC 'E' + ;LOADCP CONOUT + ;CALL + + ;LOAD FL_E_R + ;LOADCP PRINTHEXW + ;CALL + ;LOADCP NEWLINE + ;CALL + + ; check exponent range overflow + LOADCP FLOAT32_EXP_CHECK + CALL +ADDFL_6: + ; pack e_r,f_r,s_r into r + LOADREG FP + LOADC FL_E_R + ADD + LOADCP _PACKFLOAT32 + CALL + + FPADJ ADDFL_FS + RET + +; check exponent value of local var FL_E_R +; for overflow and issue runtime error on failure. +; uses stack frame of caller. +FLOAT32_EXP_CHECK: + ; check exponent range overflow + LOAD FL_E_R + LOADC FLOAT32_MAX_EXP + CMPU LE + CBRANCH FLOAT32_EXP_XT + + LOADCP FLOAT32_ERR_OVR + LOADCP _RUNTIME_ERR + JUMP +FLOAT32_EXP_XT: + RET + +; subtract floating point value b from a +; parameters: [ a, b ] +; returns: a - b +_SUBFLOAT32: + ; just flip sign bit of b and continue with _ADDFLOAT32 + LOADCP $80000000 + XOR + BRANCH _ADDFLOAT32 + +; multiply two floating point values a and b +; parameters: [ a, b ] +; returns: a * b + .EQU MULFL_FS 36 +_MULFLOAT32: + FPADJ -MULFL_FS ; same stack frame layout as _ADDFLOAT32 + + DUP + CBRANCH.NZ _MULFLOAT32_1 ; check if b is zero + ; if yes, just return zero + NIP ; remove a, take b (which is zero) as return value + BRANCH _MULFLOAT32_X +_MULFLOAT32_1: + ; unpack b into e_b and f_b + LOADREG FP + LOADC FL_E_B + ADD ; addr of FL_E_B + LOADCP _UNPACKFLOAT32 + CALL + + DUP + CBRANCH.NZ _MULFLOAT32_2 ; check if a is zero + ; if yes, return zero + ; take a (which is zero) as return value + BRANCH _MULFLOAT32_X +_MULFLOAT32_2: + ; unpack a into e_a and f_a + LOADREG FP ; addr of FL_E_A + LOADCP _UNPACKFLOAT32 + CALL + + ; s_r = s_a xor s_b + LOAD FL_S_A + LOAD FL_S_B + XOR + STORE FL_S_R + + ; e_r = e_a + e_b - bias + LOAD FL_E_A + LOAD FL_E_B + ADD + LOADC FLOAT32_BIAS + SUB + STORE FL_E_R + + ; check exponent range overflow + LOADCP FLOAT32_EXP_CHECK + CALL + ; f_r = fractmult(f_a, f_b) + LOADCP _FRACTMULT + CALL + + LOADCP NORMROUND_FL ; normalize and round + CALL + + ; pack result + LOADREG FP + LOADC FL_E_R + ADD + LOADCP _PACKFLOAT32 + CALL +_MULFLOAT32_X: + ; 32 bit float result is now on stack + FPADJ MULFL_FS + RET + +; multiply fractions. +; uses stack frame/local variables from caller. +; FL_F_B is destroyed. +; result is written to FL_R +_FRACTMULT: + LOADC FLOAT32_FRCBITS ; this is the counter which we keep on stack + + LOADC 0 ; start with result zero + STORE FL_F_R + + ; for each digit of the fraction of b, from right to left, + ; the fraction of a is added to the result, if that digit is 1. + ; on each iteration, the result is shifted right. +_FRACTMULT_1: + LOAD FL_F_R + SHR + STORE FL_F_R ; shift result frac for next iteration + + LOAD FL_F_B + LOADC FLOAT32_FRCLSB + AND ; isolate lowest bit + + CBRANCH.Z _FRACTMULT_2 ; if not set, don't add in this iteration + + LOAD FL_F_R ; otherwise, add fraction of a to result + LOAD FL_F_A + ADD + STORE FL_F_R + +_FRACTMULT_2: + LOAD FL_F_B + SHR + STORE FL_F_B ; shift fraction b for next digit + + DEC 1 ; decrease counter + DUP + CBRANCH _FRACTMULT_1 ; if not zero, next loop iteration + + DROP ; drop counter + RET + +; divide floating point value a by b +; parameters: [ a, b ] +; returns: a / b + .EQU DIVFL_FS 36 +_DIVFLOAT32: + FPADJ -DIVFL_FS ; same stack frame layout as _ADDFLOAT32 + DUP + CBRANCH.NZ _DIVFLOAT32_0 ; check b for zero + LOADCP FLOAT32_ERR_DIVZ ; if it is, we have a division by zero + LOADCP _RUNTIME_ERR ; and we issue a runtime error + JUMP +_DIVFLOAT32_0: + OVER ; check a for zero + CBRANCH.NZ _DIVFLOAT32_0_1 + ; if it is we just return zero + DROP ; remove args + DROP + LOADC 0 + BRANCH _DIVFLOAT32_XT + +_DIVFLOAT32_0_1: + ; unpack b into e_b and f_b + LOADREG FP + LOADC FL_E_B + ADD ; addr of FL_E_B + LOADCP _UNPACKFLOAT32 + CALL + ; unpack a into e_a and f_a + LOADREG FP ; addr of FL_E_A + LOADCP _UNPACKFLOAT32 + CALL + + ; s_r = s_a xor s_b + LOAD FL_S_A + LOAD FL_S_B + XOR + STORE FL_S_R + + ; e_r = e_a - e_b + bias + LOAD FL_E_A + LOAD FL_E_B + SUB + LOADC FLOAT32_BIAS + ADD + STORE FL_E_R + + ; check exponent range overflow + LOADCP FLOAT32_EXP_CHECK + CALL + ; f_r = fractdiv(f_a, f_b) + LOADCP _FRACTDIV + CALL + + LOADCP NORMROUND_FL ; normalize and round + CALL + + ; pack result + LOADREG FP + LOADC FL_E_R + ADD + LOADCP _PACKFLOAT32 + CALL +_DIVFLOAT32_XT: + ; 32 bit float result is now on stack + FPADJ DIVFL_FS + RET + +; divide fraction of a by b. +; uses stackframe of caller. +; FL_F_A is destroyed. +; places result into FL_F_R. +_FRACTDIV: + LOADC 0 + STORE FL_F_R + + LOADC FLOAT32_FRCBITS ; load counter +_FRACTDIV_1: + LOAD FL_F_R ; load result for later + LOAD FL_F_B + LOAD FL_F_A + CMPU GT + CBRANCH _FRACTDIV_2 ; if b > a, skip next section + INC 1 ; a fits into b, so add 1 to result + LOAD FL_F_A ; subtract divisor from dividend + LOAD FL_F_B + SUB + STORE FL_F_A + +_FRACTDIV_2: + SHL ; shift result left for next digit + STORE FL_F_R ; and store it again + LOAD FL_F_A ; shift the dividend left for next digit + SHL + STORE FL_F_A + + DEC 1 ; decrement counter + DUP + CBRANCH.NZ _FRACTDIV_1 ; loop if it is not zero + + DROP ; remove counter + + LOAD FL_F_R ; undo the last shift of the result + SHR + BROT ; and shift left again to make room for the exponent + STORE FL_F_R + RET + + +; normalize and round f_r. +; uses stack frame of caller. +NORMROUND_FL: + LOAD FL_F_R +NORMFL_0: + ; if overflow bit of f_r is set, scale right + DUP + LOADCP FLOAT32_OVRFLOW ; isolate overflow bit + AND + CBRANCH.Z NORMFL_1 ; if bit is zero, skip the scaling + + ; scale right: shift right f_r by one, increment e_r by one + SHR + LOAD FL_E_R + INC 1 + STORE FL_E_R + +NORMFL_1: + ; check if result is zero + DUP + CBRANCH.NZ NORMFL_1_1 + ; set exponent to something useful + LOADC 0 + STORE FL_E_R + ; clear sign flag, we don't want -0 + LOADC 0 + STORE FL_S_R + + BRANCH NORMFL_2 + + ; normalize: + ; if bit 30 of f_r is zero, scale left +NORMFL_1_1: + DUP + LOADCP FLOAT32_FRCMSBM ; isolate msb of fraction + AND + CBRANCH.NZ NORMFL_2 ; skip if bit is set + ; scale left and repeat previous step + SHL ; shift fraction + LOAD FL_E_R ; decrement exponent + DEC 1 + STORE FL_E_R + BRANCH NORMFL_1_1 ; repeat + +NORMFL_2: + ; round: + ; simple round algorithm: if the bit below + ; the least significat bit is 1, round up + ; and check the overflow bit again + DUP + LOADC FLOAT32_RNDMASK ; test rounding bit + AND + CBRANCH.Z NORMFL_3 ; if not set, skip rounding + + LOADC FLOAT32_RNDINCR + ADD + + LOADCP FLOAT32_FRCMASK ; remove rounded off bits + AND + + BRANCH NORMFL_0 ; check for overflow again +NORMFL_3: + STORE FL_F_R + RET + +; return the fractional part of a floating point number +; parameters: float32 value +; returns: float32 value + .EQU FRACTFL_EXP 12 + .EQU FRACTFL_FS 20 +_FRACTFLOAT32: + FPADJ -FRACTFL_FS + DUP ; check for zero + CBRANCH.Z FRACTFL_XT ; if yes, just return zero + LOADREG FP + LOADCP _UNPACKFLOAT32 + CALL + + LOAD FL_E_A ; remove bias from exponent + LOADC FLOAT32_BIAS + SUB + DUP + STORE FRACTFL_EXP + + LOADC 0 ; if the exponent is negative, + CMP LT ; there are no digits before the point + CBRANCH FRACTFL_PK ; and we just return the same value + + LOAD FRACTFL_EXP ; the exponent indicates how far + ; we need to shift the fraction to the left + INC 1 ; at exp 0 we need to shift by 1 + + LOADC FLOAT32_BIAS - 1 + STORE FL_E_A ; the new exponent is -1 because we + ; shifted by (old exp + 1) bits + + LOAD FL_F_A ; load fraction, shift count is already on stack +FRACTFL_L: + SHL ; shift fraction + SWAP ; swap fraction and shift count + DEC 1 ; decrement count + SWAP ; swap back shift count and fraction + OVER ; check count for zero + CBRANCH FRACTFL_L ; if not, loop + + NIP ; remove count + LOADCP FLOAT32_FRCMASK + AND ; remove superfluous bits + + DUP ; check if fraction is zero + CBRANCH.NZ FRACTFL_1 + ; if yes, directly return + BRANCH FRACTFL_XT + + ; normalize +FRACTFL_1: + DUP + LOADCP FLOAT32_FRCMSBM ; isolate msb of fraction + AND + CBRANCH.NZ FRACTFL_2 ; skip if bit is set + ; scale left and repeat previous step + SHL ; shift fraction + LOAD FL_E_A ; decrement exponent + DEC 1 + STORE FL_E_A + BRANCH FRACTFL_1 ; repeat +FRACTFL_2: + STORE FL_F_A +FRACTFL_PK: + LOADREG FP + LOADCP _PACKFLOAT32 + CALL +FRACTFL_XT: + FPADJ FRACTFL_FS + RET + +; truncate a floating point number - return +; the integer value before the decimal point. +; issues a runtime error if the integer value +; does not fit into a signed 32-bit integer. +; parameters: float32 value +; returns: integer + .EQU TRUNCFL_SHIFT 12 + .EQU TRUNCFL_FS 16 +_TRUNCFLOAT32: + FPADJ -TRUNCFL_FS + LOADREG FP + LOADCP _UNPACKFLOAT32 + CALL + + LOAD FL_E_A ; remove bias from exponent + LOADC FLOAT32_BIAS + SUB + DUP + STORE FL_E_A + + ; if the exponent + LOADC 0 ; is negative, + CMP LT ; our result is zero + CBRANCH TRUNCFL_ZERO + + ; shift fraction all the way to the right + LOAD FL_F_A ; shift fraction right by 8 bits + BROT ; by rotating 3*8 bits left + BROT ; we know that the original bits 7-0 + BROT ; are zero + + ; calculate number of bits to shift: + ; fraction bits - 1 - exponent + LOADC FLOAT32_FRCBITS - 1 + LOAD FL_E_A + SUB + DUP + STORE TRUNCFL_SHIFT + LOADC 0 ; is shift count >= 0? + CMP GE + CBRANCH TRUNCFL_2 + + ; shift count is negative, need to shift left + ; check for integer overflow first + LOAD TRUNCFL_SHIFT + NOT ; negate shift count + INC 1 + + DUP ; shift count >= bits in a word - bits in the fraction? + LOADC 32 - FLOAT32_FRCBITS + CMP GE + CBRANCH TRUNCFL_ERR ; then we have an overflow + + ; otherwise, shift n bits left +TRUNCFL_1: + DUP + CBRANCH.Z TRUNCFL_3 ; if zero, we are done + + DEC 1 ; decrement shift count + SWAP ; swap shift count and fraction + SHL ; shift fraction left + SWAP ; swap back + BRANCH TRUNCFL_1 ; and loop + +TRUNCFL_2: ; shift right, fraction is on ToS + LOAD TRUNCFL_SHIFT ; bits to shift +TRUNCFL_L1: + DUP + CBRANCH.Z TRUNCFL_3 ; if zero, we are done + + DEC 1 ; decrement shift count + SWAP ; swap shift count and fraction + SHR ; shift fraction right + SWAP ; swap back + BRANCH TRUNCFL_L1 ; and loop +TRUNCFL_3: + DROP ; drop shift count + BRANCH TRUNCFL_EXIT +TRUNCFL_ZERO: + LOADC 0 +TRUNCFL_EXIT: + LOAD FL_S_A ; check sign + CBRANCH.Z TRUNCFL_EXIT1 + ; if not zero, negate result + NOT + INC 1 +TRUNCFL_EXIT1: + FPADJ TRUNCFL_FS + RET + +TRUNCFL_ERR: + DROP + LOADCP FLOAT32_ERR_TRUNC + LOADCP _RUNTIME_ERR + JUMP + +; like _TRUNCFLOAT32, but return a float32 value +; parameters [ float value ] +; returns: float value +; TODO: write a real routine which might be faster +; than just calling _TRUNCFLOAT32 and INTTOFLOAT32. +; Also, _TRUNCFLOAT32 can cause an integer overflow +; where INT should not. +_INTFLOAT32: + LOADCP _TRUNCFLOAT32 + CALL + LOADCP _INTTOFLOAT32 + CALL + RET + + .CPOOL + +; multiply/divide a float value by a multitude of 2 +; shift count < 1: shift right (divide) +; shuft count > 0: shift left (multiply) +; parameters: [ float value, shift count ] +; returns: float value + .EQU SHF32_FS 36 + .EQU SHF32_COUNT 12 +SHIFTFLOAT32: + FPADJ -SHF32_FS + + ; store shift count parameter + STORE SHF32_COUNT + ; Unpack float value. + ; We use the result variable slot + ; because EXP_CHECK uses that. + LOADREG FP + LOADC FL_E_R + ADD + LOADCP _UNPACKFLOAT32 + CALL + + ; we just add the shift count to + ; the exponent + LOAD FL_E_R + LOAD SHF32_COUNT + ADD + STORE FL_E_R + + ; and check for overflow + LOADCP FLOAT32_EXP_CHECK + CALL + + ; pack up the result + LOADREG FP + LOADC FL_E_R + ADD + LOADCP _PACKFLOAT32 + CALL + + FPADJ SHF32_FS + RET + +; convert an integer to a float32 +; parameters: an integer +; returns: a float32 value + .EQU INTF32_FS 12 +_INTTOFLOAT32: + FPADJ -INTF32_FS + + ; is intval zero? + DUP + CBRANCH.Z INTTOFLOAT32_XT ; if yes, we are done, float zero has the same + ; representation as integer zero + + ; is intval < 0? + LOADC 0 + CMP.S0 LT + DUP + STORE FL_S_A ; store cmp result as sign flag + CBRANCH.Z INTF32_1 ; skip negate if cmp result is 0 + ; negate + NOT + INC 1 +INTF32_1: + LOADC 30 ; set counter +INTF32_L: + ; loop if bit 31 is not set: + SWAP ; swap counter and value (value is now ToS) + + LOADCP $40000000 + AND.S0 + CBRANCH INTF32_2 + ; shift left + SHL + ; swap counter and value again (counter is now ToS) + SWAP + ; decrease counter + DEC 1 + BRANCH INTF32_L +INTF32_2: + ; store shifted value as fraction + STORE FL_F_A + ; set exponent to counter + bias + LOADC FLOAT32_BIAS + ADD + STORE FL_E_A + ; pack components + LOADREG FP + LOADCP _PACKFLOAT32 + CALL + BRANCH INTTOFLOAT32_XT +INTTOFLOAT32_XT: + FPADJ INTF32_FS + RET + +; get the binary exponent of a floating point value +; (without the bias) +; parameters: [ float value ] +; returns: exponent (-128..128) +_GETFLOAT32EXP: + LOADC FLOAT32_EXPMASK + AND + LOADC FLOAT32_BIAS + SUB + RET + +; compare an integer to a floating point value +; parameters: a:integer, b: float +; calls INTTOFLOAT32 on a, then calls CMPFLOAT32 +; returns: -1 if a < b +; 0 if a = b +_CMPINTFLOAT32: + SWAP ; swap a and b, a is now on top of stack + LOADCP _INTTOFLOAT32 + CALL ; a is now a float + SWAP ; swap a and b back, b is on top of stack again + ; fallthrough to CMPFLOAT32 + +; compare two floating point values +; parameters: two floating point values a and b +; returns: -1 if a < b +; 0 if a = b +; 1 if a > b + .EQU CMPFL_FS 24 +_CMPFLOAT32: + FPADJ -CMPFL_FS + ; unpack b + LOADREG FP + LOADC FL_E_B + ADD + LOADCP _UNPACKFLOAT32 + CALL + ;unpack a + LOADREG FP + LOADCP _UNPACKFLOAT32 + CALL + + ;if sign(a) and not sign(b): + ; return -1 + ;if not sign(a) and sign(b): + ; return 1 + LOAD FL_S_A + LOAD FL_S_B + XOR + CBRANCH.Z CMPFL_2 ; jump if signs are the same + ; signs are not the same + LOAD FL_S_A + CBRANCH.Z CMPFL_1 ; jump if a is positive + ; a is negative, b must be positive, so a < b +CMPFL_M1: + LOADC -1 + BRANCH CMPFL_XT +CMPFL_1: + ; a is positive, b must be negative, so a > b + LOADC 1 + BRANCH CMPFL_XT +CMPFL_2: + ; signs are the same, compare exponents now. + ; we can compare the exponent values directly without + ; subtracting the bias because negative exponents + ; are smaller than positive exponents due to the added + ; bias. + ; if we determine a result, from now on the result + ; must be inverted if the sign of a and b is negative. + + ;if exp(a) < exp(b): + ; return -1 * sign(a) + LOAD FL_E_A + LOAD FL_E_B + CMPU GE + CBRANCH CMPFL_3 ; jump if exp(a) >= exp(b) + ; exp(a) < exp(b), so abs(a) < abs(b) + LOADC -1 +CMPFL_2_1: + ; invert result if signs of a and b are negative + LOAD FL_S_A + CBRANCH.Z CMPFL_XT ; sign is clear, no need to invert + + NOT ; negate result and exit + INC 1 + BRANCH CMPFL_XT +CMPFL_3: + ; exp(a) >= exp(b) + ; check if exp(a) > exp(b) + LOAD FL_E_A + LOAD FL_E_B + CMPU GT + CBRANCH CMPFL_5 ; jump if yes + ; exp(a) = exp(b) + ; exponents are the same, compare fractions now + + ;if frac(a) < frac(b): + ; return -1 * sign(a) + LOAD FL_F_A + LOAD FL_F_B + CMPU GE + CBRANCH CMPFL_4 ; jump if frac(a) >= frac(b) + + ; frac(a) < frac(b) + LOADC -1 + BRANCH CMPFL_2_1 ; check for inversion of result + ;if frac(a) > frac(b): + ; return 1 * neg_result +CMPFL_4: + ; frac(a) >= frac(b) + ; check if frac(a) > frac(b) + LOAD FL_F_A + LOAD FL_F_B + CMPU GT + CBRANCH CMPFL_5 ; jump if frac(a) > frac(b) + ; frac(a) = frac(b) + LOADC 0 + BRANCH CMPFL_XT +CMPFL_5: + ; exp(a) > exp(b): + ; return 1 * sign(a) + LOADC 1 + BRANCH CMPFL_2_1 ; check for inversion of result +CMPFL_XT: + FPADJ CMPFL_FS + RET + +; Negate a float32 number. +; just flip the highest bit, no +; need to unpack. +; if it is zero, do nothing, we +; do not want a -0.0 value +_NEGFLOAT32: + DUP + CBRANCH.Z _NEGFL_XT + LOADCP $80000000 + XOR +_NEGFL_XT: + RET + + .CPOOL + +FLOAT32_ERR_OVR: + .BYTE "floating point overflow",0 +FLOAT32_ERR_TRUNC: + .BYTE "integer overflow",0 +FLOAT32_ERR_DIVZ: + .BYTE "float division by zero",0 diff --git a/lib/rommon.s b/lib/rommon.s new file mode 100644 index 0000000..a967e4b --- /dev/null +++ b/lib/rommon.s @@ -0,0 +1,805 @@ + .EQU CR 13 + .EQU LF 10 + .EQU EOT 4 + .EQU ACK 6 + .EQU NAK 21 + .EQU STX 2 + .EQU UART_REG 2048 + .EQU MON_ADDR 64512 + + BRANCH 2 ; the very first instruction is not + ; executed correctly + LOADCP 65020 ; initialise FP and RP registers + STOREREG FP + LOADCP 65024 + STOREREG RP + + LOADCP MON_ADDR + LOADCP 4096 + STOREI + DROP +CMDLOOP0: + LOADC MESSAGE + LOADC PRINTLINE + CALL + +CMDLOOP: + LOADC NEWLINE + CALL + LOADC PROMPT + CALL +CMDLOOP1: + LOADC CONIN + CALL + LOADC TOUPPER + CALL + + DUP + LOADC CONOUT + CALL + + LOADC 'A' + CMP.S0 EQ + CBRANCH.Z CMD1 + LOADC CMD_A + CALL + BRANCH CMDLOOP2 +CMD1: + LOADC 'X' + CMP.S0 EQ + CBRANCH.Z CMD2 + LOADC CMD_X + CALL + BRANCH CMDLOOP2 +CMD2: + LOADC 'D' + CMP.S0 EQ + CBRANCH.Z CMD3 + LOADC CMD_D + CALL + BRANCH CMDLOOP2 +CMD3: + LOADC 'G' + CMP.S0 EQ + CBRANCH.Z CMD4 + LOADC CMD_G + CALL + BRANCH CMDLOOP2 +CMD4: + LOADC 'L' + CMP.S0 EQ + CBRANCH.Z CMD5 + LOADC CMD_L + CALL + BRANCH CMDLOOP2 +CMD5: + LOADC 'B' + CMP.S0 EQ + CBRANCH.Z CMD6 + LOADC CMD_B + CALL + BRANCH CMDLOOP2 +CMD6: + DROP + BRANCH CMDLOOP0 +CMDLOOP2: + DROP + BRANCH CMDLOOP + +; ---- Command 'A': set current address +CMD_A: + LOADC 32 + LOADC CONOUT + CALL + LOADC READHEX + CALL + CBRANCH.Z CMD_A_INVALID ; 0 if not valid input + LOADCP MON_ADDR + SWAP + STOREI + DROP ; drop STOREI address + RET +CMD_A_INVALID: + DROP + LOADC '.' + LOADC CONOUT + CALL + RET + +; ---- Command 'X': examine current address +CMD_X: + FPADJ -8 ; reserve space for 4 bytes of local variables + LOADCP MON_ADDR + LOADI + STORE 0 ; current memory address + LOADC 4 ; print 8 words + STORE 4 ; Loop counter +CMD_X_LOOP: + LOADC 32 ; print a a space + LOADC CONOUT + CALL + LOAD 0 ; load word via current address + LOADI + LOADC PRINTHEXW ; print it + CALL + LOAD 0 + INC 4 ; increment current address + STORE 0 + LOAD 4 + DEC 1 + DUP + STORE 4 + CBRANCH.NZ CMD_X_LOOP + LOADCP MON_ADDR + LOAD 0 + STOREI + DROP + FPADJ 8 + RET + +; ---- Command 'D': deposit words at current address +CMD_D: + FPADJ -4 + LOADC 4 ; max number of words + STORE 0 +CMD_D_LOOP: + LOADC 32 ; print a space + LOADC CONOUT + CALL + LOADC READHEX + CALL + DUP + CBRANCH.Z CMD_D_EXIT ; check for invalid input + SWAP ; swap return code and value + LOADCP MON_ADDR + LOADI ; get current address + SWAP ; swap address and value for STOREI + STOREI 4 ; store the value with post-increment of address + LOADCP MON_ADDR + SWAP ; swap destination address and value for STOREI + STOREI ; store the new address + DROP + LOADC 2 ; compare return code (swapped above) to 2 + CMP EQ ; check for valid input and return key + CBRANCH CMD_D_EXIT + LOAD 0 + DEC 1 + DUP + STORE 0 + CBRANCH.NZ CMD_D_LOOP +CMD_D_EXIT: + FPADJ 4 + RET + +CMD_G: + DROP ; remove input char + LOADCP NEWLINE + CALL + LOADCP MON_ADDR + LOADI + JUMP + +CMD_L: + LOADCP NEWLINE + CALL + LOADCP RCVBLOCKS + CALL + LOADCP NEWLINE + CALL + RET + +PROMPT: + LOADC '[' + LOADC CONOUT + CALL + LOADCP MON_ADDR + LOADI + LOADC PRINTHEXW + CALL + LOADC PROMPT2 + LOADC PRINTLINE + CALL + RET + +NEWLINE: + LOADC CR + LOADC CONOUT + CALL + LOADC LF + LOADC CONOUT + CALL + RET + +; print string of byte characters +; takes pointer to string on eval stack +PRINTLINE: + DUP ; duplicate address as arg to printchar + LOADC PRINTCHAR + CALL + CBRANCH.Z PRINTLINE_EXIT ; if char is zero, exit + INC 1 ; increment address + BRANCH PRINTLINE +PRINTLINE_EXIT: + DROP ; remove address from stack + RET + +; print a single character +; takes a byte pointer on eval stack +; returns character on eval stack +PRINTCHAR: + LOADI.S1.X2Y ; load word, keep address on stack + BSEL ; select byte of a word via address + DUP ; check for null byte + CBRANCH.Z PRINTCHAR_XT + DUP + LOADC CONOUT + CALL +PRINTCHAR_XT: + RET + +; print a 32-bit hexadecimal number +; takes the value on the stack + +PRINTHEXW: + BROT + DUP + LOADC PRINTHEXB + CALL + BROT + DUP + LOADC PRINTHEXB + CALL + BROT + DUP + LOADC PRINTHEXB + CALL + BROT + LOADC PRINTHEXB + CALL + RET + +PRINTHEXB: + DUP + SHR + SHR + SHR + SHR + LOADC PRINTNIBBLE + CALL + LOADC PRINTNIBBLE + CALL + RET + +PRINTNIBBLE: + LOADC 15 + AND ; isolate nibble + LOADC 10 + CMPU.S0 GE ; nibble >= 10 ? + CBRANCH.NZ PRINTNIBBLE_1 ; then print a-f + LOADC '0' ; else print 0-9 + BRANCH PRINTNIBBLE_2 +PRINTNIBBLE_1: + LOADC 55 ; 55 + 10 == 'A' +PRINTNIBBLE_2: + ADD + LOADC CONOUT + CALL + RET + +; ------ read a 8-digit hexadecimal number from the console +; stores variables on the user stack, so the FP register must be +; inizialized. +; returns two values on the eval stack: +; - return code (topmost) +; 0 - no valid number +; 1 - valid number +; 2 - valid number and enter was pressed +; - result value + +READHEX: + FPADJ -8 + LOADC 0 ; current value + STORE 0 + LOADC 8 ; max number of digits + STORE 4 ; remaining digits counter +READHEX_1: + LOADC CONIN + CALL + LOADC CR ; RETURN pressed? + CMP.S0 EQ + CBRANCH READHEX_RT + DUP + LOADC CONOUT ; echo character + CALL + LOADC CONVHEXDIGIT + CALL + LOADC -1 + CMP.S0 EQ ; invalid character? + CBRANCH.NZ READHEX_XT + LOAD 0 + SHL 2 ; shift previous nibble + SHL 2 + OR ; combine with last digit + STORE 0 + LOAD 4 + DEC 1 + DUP + STORE 4 + CBRANCH.NZ READHEX_1 + BRANCH READHEX_XT1 +READHEX_RT: ; if no digits were entered, set return code + DROP ; drop read character + LOAD 4 ;remaining digits counter + LOADC 8 + CMP NE + CBRANCH READHEX_RT2 + LOADC 0 ; no valid input + BRANCH READHEX_XT3 +READHEX_RT2: + LOADC 2 ; valid input and return pressed + BRANCH READHEX_XT3 +READHEX_XT: + DROP + LOAD 4 + LOADC 8 + CMP EQ ; if no digits were entered + CBRANCH READHEX_XT0 +READHEX_XT1: + LOADC 1 ; valid input flag + BRANCH READHEX_XT3 +READHEX_XT0: + LOADC 0 +READHEX_XT3: + LOAD 0 + SWAP + FPADJ 8 + RET + +; ------ convert character on the eval stack to upper case +TOUPPER: + LOADC 'a' + CMP.S0 LT + CBRANCH TOUPPER_XT + LOADC 'z' + CMP.S0 GT + CBRANCH TOUPPER_XT + LOADC 32 + SUB +TOUPPER_XT: + RET + +; ------ convert hexadecimal digit to integer +; ------ takes an ascii character as parameter on the eval stack +; ------ returns an integer value from 0-15 on the eval stack, +; ------ or -1 if the character was not a valid hexadecimal digit + +CONVHEXDIGIT: + LOADC TOUPPER + CALL + LOADC '0' + CMP.S0 LT ; character < '0'? + CBRANCH.NZ CONVHEXDIGIT_ERR + LOADC '9' + CMP.S0 GT ; character > '9'? + CBRANCH.NZ CONVHEXDIGIT_ISALPHA + LOADC '0' ; character is between '0' and '9', subtract '0' + SUB + BRANCH CONVHEXDIGIT_NBL +CONVHEXDIGIT_ISALPHA: + LOADC 'A' + CMP.S0 LT ; character < 'A'? + CBRANCH.NZ CONVHEXDIGIT_ERR + LOADC 'F' + CMP.S0 GT ; character > 'F'? + CBRANCH.NZ CONVHEXDIGIT_ERR + LOADC 55 ; character is between 'A' and 'F', subtract ('A' - 10) + SUB +CONVHEXDIGIT_NBL: + RET +CONVHEXDIGIT_ERR: + DROP ; remove character from stack + LOADC -1 ; error + RET + +; --------- output a character on serial console +; --------- takes a character (padded to a word) on the eval stack +CONOUT: + LOADC UART_REG ; address of UART register + LOADI ; load status + LOADC 256 ; check bit 8 (tx_busy) + AND + CBRANCH.NZ CONOUT ; loop if bit 8 is not zero + + ; transmitter is idle now, write character + LOADC UART_REG ; address of UART register + SWAP ; swap character and address for STOREI + LOADC 1024 ; TX enable bit + OR ; OR in the character + STOREI + DROP + RET + +; ---- wait until a character is received and return it on eval stack +CONIN: + LOADC WAITFORBYTE + CALL + LOADC -1 ; -1 means timeout + CMP.S0 NE + CBRANCH CONIN_XT ; exit if no timeout + DROP ; remove last result + BRANCH CONIN +CONIN_XT: + RET + + + .EQU L_BLOCKSIZE 32 + .EQU L_WORDSIZE 4 + .EQU CKSUM_PATTERN $AFFECAFE +RCVBLOCKS: + LOADCP MON_ADDR ; pointer to current write position, + LOADI ; kept on stack +RCVBLOCKS_L: + LOADC WAITFORBYTE ; read header byte + CALL + LOADC -1 + CMP.S0 EQ + CBRANCH RCVBLOCKS_XT ; exit on timeout + + ; check for EOT -> end + LOADC EOT + CMP.S0 EQ + CBRANCH RCVBLOCKS_XT + + ; check for STX -> read block + LOADC STX + CMP.S0 EQ + CBRANCH RCVBLOCKS_CONT + + ; anything else -> send NAK + BRANCH RCVBLOCKS_RETRY + +RCVBLOCKS_CONT: + DROP ; remove header byte + DUP ; duplicate pointer + LOADC READBLOCK + CALL + LOADC -1 + CMP.S0 EQ ; check for timeout + CBRANCH RCVBLOCKS_XT ; exit on timeout + + LOADC -2 + CMP.S0 EQ ; check for checksum error + CBRANCH RCVBLOCKS_RETRY + + DROP ; remove return code + LOADC L_BLOCKSIZE ; advance pointer + ADD + + LOADC ACK ; send ACK + LOADC CONOUT + CALL + + ; next block + BRANCH RCVBLOCKS_L + +RCVBLOCKS_RETRY: + DROP ; remove read byte + ; send NAK + LOADC NAK + LOADC CONOUT + CALL + + ; next block + BRANCH RCVBLOCKS_L + +RCVBLOCKS_XT: + DROP ; remove pointer + DROP ; remove read byte + RET + + +; ---- read a sequence of binary words and store into memory +; - arguments: pointer to memory area +READBLOCK: + FPADJ -12 + STORE 0 ; buffer pointer + LOADCP L_BLOCKSIZE + STORE 4 ; remaining bytes + LOADC 0 + STORE 8 ; checksum +READBLOCK_L: + LOADCP READWORD ; read a word + CALL + LOADC -1 ; check for timeout + CMP EQ + CBRANCH.NZ READBLOCK_ERR + + ; DUP ; debug + ; LOADC PRINTHEXW + ; CALL + + + DUP ; duplicate read word + LOAD 8 ; load checksum + ADD ; checksum = ((checksum + data) ^ pattern) << 1 + LOADCP CKSUM_PATTERN + XOR + SHL + STORE 8 ; store new checkcsum + + LOAD 0 ; load buffer pointer + SWAP ; swap value and pointer for STOREI + STOREI 4 ; store word and increment pointer + STORE 0 ; store pointer + + LOAD 4 ; load remaining bytes + DEC L_WORDSIZE ; decrement by word size + DUP + STORE 4 ; store + CBRANCH.NZ READBLOCK_L ; loop if remaining words not zero + + + LOADCP READWORD ; read checksum + CALL + LOADC -1 ; check for timeout + CMP EQ + CBRANCH READBLOCK_ERR + + LOAD 8 ; load checksum + CMP EQ + CBRANCH READBLOCK_OK + LOADC -2 ; return code for checksum error + BRANCH READBLOCK_XT +READBLOCK_OK: + LOADC 0 ; return 0 +READBLOCK_XT: + FPADJ 12 + RET + +READBLOCK_ERR: + DROP ; remove result + LOAD 4 ; return number of missing bytes + FPADJ 8 + RET + +; --- read four bytes (msb to lsb) and return as word +; returns: word, error code (-1 for error, 0 otherwise) + +READWORD: + LOADCP WAITFORBYTE + CALL + DUP + LOADC -1 ; check for error + CMP EQ + CBRANCH.NZ READWORD_ERR + ; first byte is now on stack + BROT ; rotate byte left + + LOADCP WAITFORBYTE + CALL + DUP + LOADC -1 ; check for error + CMP EQ + CBRANCH.NZ READWORD_ERR + ; second byte is now on stack + OR ; OR last byte with this byte + BROT ; rotate bytes left + + LOADCP WAITFORBYTE + CALL + DUP + LOADC -1 ; check for error + CMP EQ + CBRANCH.NZ READWORD_ERR + ; third byte is now on stack + OR ; OR last byte with this byte + BROT + + LOADCP WAITFORBYTE + CALL + DUP + LOADC -1 ; check for error + CMP EQ + CBRANCH.NZ READWORD_ERR + ; fourth byte is now on stack + OR ; OR last byte with this byte + + LOADC 0 ; error code (0: no error) + RET + +READWORD_ERR: + LOADC -1 ; error code + RET + +;---- wait a fixed amount of cycles for a character to be +; received on the UART. +; returns character or -1 on timeout + + .EQU MAX_WAIT 20000000 +WAITFORBYTE: + LOADCP MAX_WAIT ; maximum wait loops +WAITFORBYTE_L: + LOADC UART_REG ; address of UART register + LOADI ; load status + LOADC 512 ; check bit 9 (rx_avail) + AND + CBRANCH WAITFORBYTE_RX ; if bit 9 is one, a character is available + DEC 1 + DUP + CBRANCH.NZ WAITFORBYTE_L + DROP ; remove wait counter from stack + LOADC -1 ; error code + RET +WAITFORBYTE_RX: + DROP ; remove wait counter from stack + LOADC UART_REG + LOADI ; read register again + LOADC 255 ; mask status bits + AND + LOADC UART_REG ; I/O address + LOADC 512 ; set bit 9 (rx_clear) + STOREI ; write register + DROP ; remove address left by STOREI + RET + + .CPOOL + +;---- boot from SD-card + + ; declare buffer addresses used by sdcardlib.s + .EQU CSD_BUF 63984 + .EQU CARD_BUF 64000 +CMD_B: + DROP ; remove input char + LOADCP NEWLINE + CALL + + FPADJ -4 + ; initialize card + LOADC INITSDCARD + CALL + + ; read partition block + LOADC 0 + LOADC CARDREADBLK + CALL + + DUP ; non-zero return code means error + CBRANCH.Z CMD_B_1 +CMD_B_ERR: + LOADC PRINTHEXW ; print error code + CALL + LOADC NEWLINE + CALL + LOADC 0 ; if we return, we need to + ; put a fake input char back on the + ; stack because the main loop will + ; try to remove it + FPADJ 4 + RET + +CMD_B_1: + DROP ; remove error code + ; check boot partition slot (boot flag) + LOADCP CARD_BUF,104 ; offset partition flags second part slot + LOADI + LOADC 2 ; PartFlags [PartBoot] + CMP EQ + CBRANCH CMD_B_C + + ; no boot partition + LOADC $B0 + BRANCH CMD_B_ERR + +CMD_B_C: + ; get start block + LOADCP CARD_BUF,108 ; offset startBlock + LOADI + ; get block count + LOADCP CARD_BUF,124 ; offset bootBlocks + LOADI + + FPADJ -4 ; allocate space for address var + LOADCP MON_ADDR + LOADI + STORE 0 ; initialize dest addr +CMD_B_L: + ; read block + OVER ; duplicate block no + LOADC CARDREADBLK + CALL + + DUP ; check for error + CBRANCH.Z CMD_B_C2 ; continue if zero (no error) + + NIP ; remove start and count, keep error code + NIP + BRANCH CMD_B_ERR +CMD_B_C2: DROP ; remove error code +CMD_B_2: + ; copy to destination + LOAD 0 ; dest addr + LOADC COPY_BLK + CALL + + ; decrement count and loop + LOAD 0 ; increment dest addr + LOADC 512 + ADD + STORE 0 + + SWAP ; swap block no/count, blockno is now ToS + INC 1 + SWAP ; count is now ToS + DEC 1 + DUP + CBRANCH.NZ CMD_B_L ; if not zero, loop + + ; jump to coreloader + DROP + DROP + FPADJ 4 + LOADCP MON_ADDR + LOADI + JUMP + +CMD_B_XT: + FPADJ 4 + RET + +; copy a sdcard block to destination address +; block size is always 512 byte, source +; is always CARD_BUF +; parameters: dest addr +COPY_BLK: + FPADJ -4 + LOADC 128 ; word count + STORE 0 + + LOADCP CARD_BUF ; src addr +COPY_BLK1: + SWAP + ; [ src addr, dest addr ] + OVER ; [ saddr, daddr, saddr ] + LOADI ; [ saddr, daddr, sword ] + STOREI 4 ; [ saddr, daddr + 4 ] + SWAP ; [ daddr + 4, saddr ] + INC 4 ; [ daddr + 4, saddr + 4] + + LOAD 0 ; load and decrement counter + DEC 1 + DUP + STORE 0 ; store it again + CBRANCH.NZ COPY_BLK1 ; if not zero, loop + + DROP ; remove saddr and daddr + DROP + + FPADJ 4 + RET + + .CPOOL + +; wait approx. 1 millisecond +; +; 83.333 MHz Clock, three instructions a 4 cycles +; 83333 / 12 = 6944.4166 +; works only if executed without wait states (i.e. +; from BRAM/SRAM) +WAIT1MSEC: + LOADCP 6944 +WAIT1LOOP: + DEC 1 + DUP + CBRANCH.NZ WAIT1LOOP + DROP + RET + +%include "sdcardboot.s" + .CPOOL +MESSAGE: + .BYTE 13,10,"ROM Monitor v3.0.3", 13, 10, + "Set A)ddress D)eposit eX)amine L)oad G)o B)oot",13,10,0 +PROMPT2: + .BYTE "]> ",0 +END: diff --git a/lib/sdcardboot.s b/lib/sdcardboot.s new file mode 100644 index 0000000..f3b7c9c --- /dev/null +++ b/lib/sdcardboot.s @@ -0,0 +1,613 @@ + .EQU SPIREG $880 + + .EQU SPI_CTRL_WRITE %100000000000000 + .EQU SPI_RX_FILTER_EN %010000000000000 + .EQU SPI_TXRX_EN %001000000000000 + .EQU SPI_CLK_F_EN %000100000000000 + .EQU SPI_CLK_DIV_WR %000010000000000 + .EQU SPI_RX_RD %000001000000000 + .EQU SPI_TX_WR %000000100000000 + + .EQU SPI_C_D %100000000000000 + .EQU SPI_C_CHG %010000000000000 + .EQU SPDI_C_BUSY %001000000000000 + .EQU SPI_TX_RDY %000100000000000 + .EQU SPI_TX_EMPTY %000010000000000 + .EQU SPI_RX_AVAIL %000001000000000 + .EQU SPI_RX_OVR %000000100000000 + + .EQU SPI_TXRX_EN_MASK ~SPI_TXRX_EN + +_WAIT: + LOADC 10 +_WAITL: + LOADC WAIT1MSEC + CALL + DEC 1 + DUP + CBRANCH.NZ _WAITL + DROP + RET + +INITSDCARD: + LOADC WAIT1MSEC + CALL + + LOADC _SPIINIT1 + CALL + + ;LOADC 'I' + ;LOADCP CONOUT + ;CALL + + LOADC _WAITSPITXRDY + CALL + + ;LOADC 'W' + ;LOADCP CONOUT + ;CALL + + ; send RESET CARD command + LOADC $95 ; send cmd0 with arg 0 and checksum $95 + LOADC $0 + LOADC $0 + LOADC SENDCMD_R1 + CALL + + DROP ; TODO: handle errors + ;LOADCP PRINTHEXW ; print status returned by the card + ;CALL + ;LOADCP NEWLINE + ;CALL + + ;LOADC '9' + ;LOADCP CONOUT + ;CALL + + LOADC _WAITSPITXRDY + CALL + + LOADC _WAIT + CALL + + ;LOADC '1' + ;LOADCP CONOUT + ;CALL + + LOADC $87 + LOADC $01AA + LOADC $8 + LOADC SENDCMD_R7 + CALL + + DROP + + LOADC _WAITSPITXRDY + CALL + + ;LOADC '2' + ;LOADCP CONOUT + ;CALL + + ;LOADCP _WAIT + ;CALL + + ;LOADC '.' + ;LOADCP CONOUT + ;CALL + + LOADC CARDINITV2 + CALL + + ;LOADC '+' + ;LOADCP CONOUT + ;CALL + + + LOADC CARDFASTCLK + CALL + + ;LOADC '3' + ;LOADCP CONOUT + ;CALL + + ; CMD16: set block size to 512 byte + LOADC 0 + LOADC 512 + LOADC 16 + LOADCP SENDCMD_R1 + CALL + + DROP + + ;LOADCP _WAIT + ;CALL + + ;LOADC '4' + ;LOADCP CONOUT + ;CALL + + RET + +; read a 512-byte-block from the card +; args: block number +; returns: 0 on success +CARDREADBLK: + LOADC 128 ; number of words in a block + SWAP ; move block number up the stack + LOADCP CARD_BUF + SWAP + LOADC 0 + SWAP + LOADC 17 ; CMD17: read block + LOADC SENDCMD_PKT + CALL + RET + +; send the card initialization command +; wait until the card responds +CARDINITV2: + LOADC 100 ; try up to 100 times +CARD_LOOP1: + LOADC 50 ; wait 50 msec +CARD_LOOP2: + LOADC WAIT1MSEC + CALL + DEC 1 + DUP + CBRANCH.NZ CARD_LOOP2 + DROP ; remove loop count value + + LOADC $0 + LOADC $0 + LOADC 58 + LOADC SENDCMD_R7 ; send CMD58 + CALL + DROP ; ignore result (why?) + + LOADC $0 + LOADCP $40000000 + LOADC 41 + LOADC SENDACMD_R1 ; send ACMD41 + CALL + + CBRANCH.Z CARD_OK ; if result is zero, the command succeded + ; and the card initialization is finished + DEC 1 + DUP + CBRANCH.NZ CARD_LOOP1 + DROP ; remove outer loop count value + + RET +CARD_OK: + DROP ; remove outer loop count value + + ; CMD16: set block size to 512 byte + LOADC 0 + LOADC 512 + LOADC 16 + LOADC SENDCMD_R1 + CALL + DROP ; ignore return value + + RET + +; set fast transfer rate +CARDFASTCLK: + LOADC SPIREG + ; set clock divider to ~2,6MHz + LOADC SPI_CLK_DIV_WR+10 + STOREI + DROP + RET + +; perform first phase of card initialization +; which is to enable clock and wait a bit +; leaves the clock running +_SPIINIT1: + LOADC SPIREG + ; set clock divider to ~325KHz + LOADC SPI_CLK_DIV_WR+64 + STOREI + DROP + + ; clear all flags + enable clock + ; /CS and MOSI are default high + LOADC SPIREG + LOADCP SPI_CTRL_WRITE,SPI_CLK_F_EN + STOREI + DROP + + ; we should wait at least for 74 clock cycles now + LOADC 2 ; wait 2 msec, that should be ~300 cycles +_SPIINIT1L: + LOADC WAIT1MSEC + CALL + DEC 1 + DUP + CBRANCH.NZ _SPIINIT1L + DROP + + LOADC SPIREG + LOADCP SPI_CTRL_WRITE ; disable clock + STOREI + DROP + + LOADCP WAIT1MSEC + CALL + + RET + +; wait for transmission to finish +; (wait for TX_EMPTY bit) +_SPIWAITTX: + LOADC SPIREG + LOADI + LOADCP SPI_TX_EMPTY + AND + CBRANCH.Z _SPIWAITTX + RET + +; finalize a command that has been sent: +; wait until the transmitter is idle +; then disable clock and set MOSI high +_SPIENDCMD: + LOADC $FF + LOADC _SENDBYTE + CALL + LOADC $FF + LOADC _SENDBYTE + CALL + + ;LOADC 'E' + ;LOADCP CONOUT + ;CALL + + LOADC _SPIWAITTX + CALL + + ;LOADC 'w' + ;LOADCP CONOUT + ;CALL + LOADC _WAIT_S ; wait a short time + CALL + + LOADC SPIREG + LOADCP SPI_IDLE_FLAGS ; turn off transceiver + LOADI + STOREI + DROP + + ; wait for a few instructions + LOADC 100 +SPIEND_LP: DEC 1 + DUP + CBRANCH.NZ SPIEND_LP + DROP + + RET + +_WAIT_S: + LOADC 100 +_WAIT_S_L: + DEC 1 + DUP + CBRANCH.NZ _WAIT_S_L + DROP + RET + +; clear RX fifo +CLEAR_RX_FIFO: +CLEAR_RX_L1: + LOADC SPIREG + LOADI + + ;DUP + ;LOADCP PRINTHEXW + ;CALL + ;LOADCP NEWLINE + ;CALL + + LOADC SPI_RX_AVAIL + AND + CBRANCH.Z CLEAR_RX_X + LOADC SPIREG + LOADC SPI_RX_RD + STOREI + DROP + + ; FIXME: it seems that this + ; does not remove a byte from the fifo, + ; rx_avail stays on, but only after the first + ; byte has been received and read + + ;LOADC 'x' + ;LOADCP CONOUT + ;CALL + + BRANCH CLEAR_RX_L1 +CLEAR_RX_X: + RET + +_WAITSPITXRDY: + LOADC SPIREG + LOADI + LOADCP SPI_TX_RDY + AND + CBRANCH.Z _WAITSPITXRDY + RET + +; send a command and receive a data packet response +; args: packet size in words, buffer pointer +; checksum byte, 32-bit cmd arg, cmd number +; returns: 0 on success +SENDCMD_PKT: + ; first send the command + LOADC SENDCMD_0 + CALL + + LOADC _RCVBYTE ; receive R1 response + CALL + + CBRANCH.NZ SENDCMD_PKT_E ; on success we get 0 + + ; now wait for data token +SENDCMD_PKT_L: + LOADC _RCVBYTE + CALL + LOADC $FF + CMP EQ + CBRANCH SENDCMD_PKT_L + + ; parameters for _RCVWORDS are on the stack now + LOADC _RCVWORDS + CALL + + ; receive 2 crc bytes + LOADC _RCVBYTE + CALL + BROT + LOADC _RCVBYTE + CALL + OR + + ; terminate command + LOADC _SPIENDCMD + CALL + + DROP ; we ignore the checksum for now + + LOADC 0 + RET +SENDCMD_PKT_E: + DROP ; remove remaining args + DROP + LOADC -1 ; return code for error + RET + +; send a command and receive a 1-byte-response (R1) +; args: checksum byte, 32-bit cmd arg, cmd number +; returns: received byte +SENDCMD_R1: + LOADC SENDCMD_0 + CALL + + LOADC _RCVBYTE + CALL + + ;LOADC 'R' + ;LOADCP CONOUT + ;CALL + + ;terminate command (/cs high, disable clock) + LOADC _SPIENDCMD + CALL + + RET + +; send a command +; args: checksum byte, 32-bit cmd arg, cmd number +SENDCMD_0: + ; clear RX FIFO first + LOADC CLEAR_RX_FIFO + CALL + + ;LOADC '>' + ;LOADCP CONOUT + ;CALL + + ; cmd byte is at TOS at this point + LOADC $40 ; or in start of frame bit + OR + LOADC _SENDBYTE + CALL + ; cmd arg is at TOS now + LOADC _SENDWORD + CALL + ; checksum byte is at TOS now + LOADC _SENDBYTE + CALL + + LOADC _XCVR_ENABLE ; enable transceiver last, + CALL ; a complete command should + RET ; fit into the tx fifo + +; send ACMD and receive a 1-byte-response (R1) +; args: checksum byte, 32-bit cmd arg, ACMD number +; returns: received byte or -1 if first response byte +; indicated an error +SENDACMD_R1: + LOADC $0 + LOADC $0 + LOADC 55 ; send CMD55 + LOADC SENDCMD_R1 + CALL + + LOADC 1 ; 1 = idle state, no errors + CMP NE + CBRANCH.NZ SENDACMD_ERR + + ; pass our args to SENDCMD_R1 + LOADC SENDCMD_R1 + CALL + RET + +SENDACMD_ERR: + LOADCP -1 + RET + +; send a command and receive a 4+1-byte-response (R7) +; args: checksum byte, 32-bit cmd arg, cmd number +; returns: received word or -1 if first response byte +; indicated an error + +SENDCMD_R7: + ; send the command + LOADC SENDCMD_0 + CALL + + ;LOADC '7' + ;LOADCP CONOUT + ;CALL + + LOADC _RCVBYTE + CALL + + LOADC _RCVWORD + CALL + + ;terminate command (/cs high, disable clock) + LOADC _SPIENDCMD + CALL + + SWAP ; swap 1st response byte with received word + LOADC %011111110 ; check for any error flags + AND + CBRANCH.Z SENDCMD_R7_NOERR + DROP + LOADC -1 +SENDCMD_R7_NOERR: + RET + +; send a word as 4 bytes, msb first +_SENDWORD: + DUP ; remember original value for later + + BROT ; rotate msb to lsb (byte 0) + LOADC 255 + AND.S0 ; isolate byte, keep previous value + LOADC _SENDBYTE + CALL + + BROT ; byte 1 + LOADC 255 + AND.S0 + LOADC _SENDBYTE + CALL + + BROT ; byte 2 + LOADC 255 + AND + LOADC _SENDBYTE + CALL + + ; byte 3 is already on the stack + LOADC 255 + AND + LOADC _SENDBYTE + CALL + + RET + +; receive multiple 4-byte-words and store into +; memory buffer +; args: number of words, pointer to buffer +_RCVWORDS: + FPADJ -4 + STORE 0 ; store pointer arg into local variable + ; keep counter on stack +_RCVWORDS_LP: + LOAD 0 ; load buf pointer for STOREI + LOADC _RCVWORD + CALL ; receive a word + STOREI 4 ; store to buf with postincrement + STORE 0 ; store pointer variable + + DEC 1 ; decrement word counter + DUP + CBRANCH.NZ _RCVWORDS_LP ; if not null, loop + DROP ; remove counter value + + FPADJ 4 + RET + +; receive 4 bytes, return as word +_RCVWORD: + LOADC _RCVBYTE ; receive first byte + CALL + BROT ; rotate byte to left + + LOADC _RCVBYTE ; receive second byte + CALL + OR ; or first and second byte together + BROT ; rotate 1st + 2nd to left + + LOADC _RCVBYTE ; receive third byte + CALL + OR + BROT + + LOADCP _RCVBYTE ; receive fourth byte + CALL + OR + RET + +_XCVR_ENABLE: + LOADC SPIREG + LOADC SPI_TX_FLAGS + LOADI + STOREI + DROP + RET + +; send a byte +; args: byte to be sent +_SENDBYTE: + LOADC SPIREG + LOADI ; load spi io register + LOADCP SPI_TX_RDY + AND ; check tx_rdy bit + CBRANCH.Z _SENDBYTE ; if not set, loop + + LOADC SPI_TX_WR ; TX_WR bit + OR ; OR in byte to be send + + LOADC SPIREG + SWAP ; swap value and addr for STOREI + STOREI ; store word (flags + data) to io register + DROP ; remove STOREI result + + RET + +; receive a byte. receiver must be enabled. +; returns: received byte +_RCVBYTE: + LOADC SPIREG + LOADI ; load spi io register + LOADC SPI_RX_AVAIL + AND.S0 ; check rx_avail bit, keep original value + CBRANCH.NZ RECVGOTIT + DROP ; rx_avail not set, remove register value and loop + BRANCH _RCVBYTE +RECVGOTIT: + LOADC SPIREG + LOADC SPI_RX_RD ; remove one byte from rx fifo + STOREI + DROP + + LOADC 255 + AND ; keep bits 7-0 + RET + +SPI_TX_FLAGS: .WORD SPI_CTRL_WRITE + SPI_TXRX_EN + SPI_RX_FILTER_EN +SPI_IDLE_FLAGS: .WORD SPI_CTRL_WRITE diff --git a/lib/sdcardlib.s b/lib/sdcardlib.s new file mode 100644 index 0000000..9b45e05 --- /dev/null +++ b/lib/sdcardlib.s @@ -0,0 +1,795 @@ +; Copyright 2021-2024 Sebastian Lederer. See the file LICENSE.md for details + .EQU SPIREG $880 + + .EQU SPI_CTRL_WRITE %100000000000000 + .EQU SPI_RX_FILTER_EN %010000000000000 + .EQU SPI_TXRX_EN %001000000000000 + .EQU SPI_CLK_F_EN %000100000000000 + .EQU SPI_CLK_DIV_WR %000010000000000 + .EQU SPI_RX_RD %000001000000000 + .EQU SPI_TX_WR %000000100000000 + + .EQU SPI_C_D %100000000000000 + .EQU SPI_C_CHG %010000000000000 + .EQU SPDI_C_BUSY %001000000000000 + .EQU SPI_TX_RDY %000100000000000 + .EQU SPI_TX_EMPTY %000010000000000 + .EQU SPI_RX_AVAIL %000001000000000 + .EQU SPI_RX_OVR %000000100000000 + + .EQU SPI_TXRX_EN_MASK ~SPI_TXRX_EN + +_WAIT: + LOADC 10 +_WAITL: + LOADCP WAIT1MSEC + CALL + DEC 1 + DUP + CBRANCH.NZ _WAITL + DROP + RET + +INITSDCARD: + LOADCP WAIT1MSEC + CALL + + LOADCP _SPIINIT1 + CALL + + ;LOADC 'I' + ;LOADCP CONOUT + ;CALL + + LOADCP _WAITSPITXRDY + CALL + + ;LOADC 'W' + ;LOADCP CONOUT + ;CALL + + ; send RESET CARD command + LOADC $95 ; send cmd0 with arg 0 and checksum $95 + LOADC $0 + LOADC $0 + LOADCP SENDCMD_R1 + CALL + + DROP ; TODO: handle errors + ;LOADCP PRINTHEXW ; print status returned by the card + ;CALL + ;LOADCP NEWLINE + ;CALL + + ;LOADC '9' + ;LOADCP CONOUT + ;CALL + + LOADCP _WAITSPITXRDY + CALL + + LOADCP _WAIT + CALL + + ;LOADC '1' + ;LOADCP CONOUT + ;CALL + + LOADC $87 + LOADC $01AA + LOADC $8 + LOADCP SENDCMD_R7 + CALL + + DROP + + LOADCP _WAITSPITXRDY + CALL + + ;LOADC '2' + ;LOADCP CONOUT + ;CALL + + ;LOADCP _WAIT + ;CALL + + ;LOADC '.' + ;LOADCP CONOUT + ;CALL + + LOADCP CARDINITV2 + CALL + + ;LOADC '+' + ;LOADCP CONOUT + ;CALL + + + LOADCP CARDFASTCLK + CALL + + ;LOADC '3' + ;LOADCP CONOUT + ;CALL + + ; CMD16: set block size to 512 byte + LOADC 0 + LOADC 512 + LOADC 16 + LOADCP SENDCMD_R1 + CALL + + DROP + + ;LOADCP _WAIT + ;CALL + + ;LOADC '4' + ;LOADCP CONOUT + ;CALL + + RET + +; read a 512-byte-block from the card +; args: block number +; returns: 0 on success +CARDREADBLK: + LOADC 128 ; number of words in a block + SWAP ; move block number up the stack + LOADCP CARD_BUF + SWAP + LOADC 0 + SWAP + LOADC 17 ; CMD17: read block + LOADCP SENDCMD_PKT + CALL + RET + +; determine number of blocks +; returns: number of blocks or -1 on error +CARDSIZE: + LOADC 4 + LOADCP CSD_BUF + LOADC 0 + LOADC 0 + LOADC 9 + LOADCP SENDCMD_PKT ; send CMD9 + CALL + + CBRANCH.NZ CARDSIZE_ERR ; if response is zero, an error occurred + + ; take bytes 7, 8 and 9 from CSD data + ; and add 1 to get card size in ksectors + LOADCP CSD_BUF + INC 4 + LOADI + LOADC $3F ; get byte 7 (bits 22-16) + AND + BROT + BROT + + LOADCP CSD_BUF ; get bytes 8 and 9 (bits 15-0) + INC 8 + LOADI + BROT + BROT + LOADCP $FFFF + AND + + OR + + INC 1 + + BROT + SHL 2; multiply by 1024 to get size in sectors + + RET + +CARDSIZE_ERR: + LOADC -1 + RET + +; returns 1 if the card was changed, 0 otherwise +CARDCHANGED: + LOADCP SPIREG + LOADI + LOADCP SPI_C_CHG + AND + LOADC 0 + CMPU NE + RET + +; write a 512-byte-block to the card +; args: block number +; returns: 0 on success +CARDWRITEBLK: + LOADC 128 ; number of words in a block + SWAP ; move block number up the stack + LOADCP CARD_BUF + SWAP + LOADC 0 + SWAP + LOADC 24 ; CMD24: write block + LOADCP SENDCMD_TXPKT + CALL + RET +; send the card initialization command +; wait until the card responds +CARDINITV2: + LOADC 100 ; try up to 100 times +CARD_LOOP1: + LOADC 50 ; wait 50 msec +CARD_LOOP2: + LOADCP WAIT1MSEC + CALL + DEC 1 + DUP + CBRANCH.NZ CARD_LOOP2 + DROP ; remove loop count value + + LOADC $0 + LOADC $0 + LOADC 58 + LOADCP SENDCMD_R7 ; send CMD58 + CALL + DROP ; ignore result (why?) + + LOADC $0 + LOADCP $40000000 + LOADC 41 + LOADCP SENDACMD_R1 ; send ACMD41 + CALL + + CBRANCH.Z CARD_OK ; if result is zero, the command succeded + ; and the card initialization is finished + DEC 1 + DUP + CBRANCH.NZ CARD_LOOP1 + DROP ; remove outer loop count value + + RET +CARD_OK: + DROP ; remove outer loop count value + + ; CMD16: set block size to 512 byte + LOADC 0 + LOADC 512 + LOADC 16 + LOADCP SENDCMD_R1 + CALL + DROP ; ignore return value + + RET + +; set fast transfer rate +CARDFASTCLK: + LOADC SPIREG + ; set clock divider to ~2,6MHz + LOADCP SPI_CLK_DIV_WR,10 ; using the LOADCP with offset syntax here + STOREI + DROP + RET + +; perform first phase of card initialization +; which is to enable clock and wait a bit +; leaves the clock running +_SPIINIT1: + LOADC SPIREG + ; set clock divider to ~325KHz + LOADCP SPI_CLK_DIV_WR,64 ; LOADCP with offset + STOREI + DROP + + ; clear all flags + enable clock + ; /CS and MOSI are default high + LOADC SPIREG + LOADCP SPI_CTRL_WRITE,SPI_CLK_F_EN + STOREI + DROP + + ; we should wait at least for 74 clock cycles now + LOADC 2 ; wait 2 msec, that should be ~300 cycles +_SPIINIT1L: + LOADCP WAIT1MSEC + CALL + DEC 1 + DUP + CBRANCH.NZ _SPIINIT1L + DROP + + LOADC SPIREG + LOADCP SPI_CTRL_WRITE ; disable clock + STOREI + DROP + + LOADCP WAIT1MSEC + CALL + + RET + +; wait for transmission to finish +; (wait for TX_EMPTY bit) +_SPIWAITTX: + LOADC SPIREG + LOADI + LOADCP SPI_TX_EMPTY + AND + CBRANCH.Z _SPIWAITTX + RET + +; finalize a command that has been sent: +; wait until the transmitter is idle +; then disable clock and set MOSI high +_SPIENDCMD: + LOADCP $FF + LOADCP _SENDBYTE + CALL + LOADCP $FF + LOADCP _SENDBYTE + CALL + + ;LOADC 'E' + ;LOADCP CONOUT + ;CALL + + LOADCP _SPIWAITTX + CALL + + ;LOADC 'w' + ;LOADCP CONOUT + ;CALL + LOADCP _WAIT_S ; wait a short time + CALL + + LOADC SPIREG + LOADCP SPI_IDLE_FLAGS ; turn off transceiver + LOADI + STOREI + DROP + + ; wait for a few instructions + LOADC 100 +SPIEND_LP: DEC 1 + DUP + CBRANCH.NZ SPIEND_LP + DROP + + RET + +_WAIT_S: + LOADC 100 +_WAIT_S_L: + DEC 1 + DUP + CBRANCH.NZ _WAIT_S_L + DROP + RET + +; clear RX fifo +CLEAR_RX_FIFO: +CLEAR_RX_L1: + LOADC SPIREG + LOADI + + ;DUP + ;LOADCP PRINTHEXW + ;CALL + ;LOADCP NEWLINE + ;CALL + + LOADC SPI_RX_AVAIL + AND + CBRANCH.Z CLEAR_RX_X + LOADC SPIREG + LOADC SPI_RX_RD + STOREI + DROP + + ; FIXME: it seems that this + ; does not remove a byte from the fifo, + ; rx_avail stays on, but only after the first + ; byte has been received and read + + ;LOADC 'x' + ;LOADCP CONOUT + ;CALL + + BRANCH CLEAR_RX_L1 +CLEAR_RX_X: + RET + +_WAITSPITXRDY: + LOADC SPIREG + LOADI + LOADCP SPI_TX_RDY + AND + CBRANCH.Z _WAITSPITXRDY + RET + +; send a command and receive a data packet response +; args: packet size in words, buffer pointer +; checksum byte, 32-bit cmd arg, cmd number +; returns: 0 on success +SENDCMD_PKT: + ; first send the command + LOADCP SENDCMD_0 + CALL + + LOADCP _RCVBYTE ; receive R1 response + CALL + + CBRANCH.NZ SENDCMD_PKT_E ; on success we get 0 + + ; now wait for data token +SENDCMD_PKT_L: + LOADCP _RCVBYTE + CALL + LOADC $FF + CMP EQ + CBRANCH SENDCMD_PKT_L + + ; parameters for _RCVWORDS are on the stack now + LOADCP _RCVWORDS + CALL + + ; receive 2 crc bytes + LOADCP _RCVBYTE + CALL + BROT + LOADCP _RCVBYTE + CALL + OR + + ; terminate command + LOADCP _SPIENDCMD + CALL + + DROP ; we ignore the checksum for now + + LOADC 0 + RET +SENDCMD_PKT_E: + DROP ; remove remaining args + DROP + LOADC -1 ; return code for error + RET + +; send a command and send a data packet +; args: packet size in words, buffer pointer +; checksum byte, 32-bit cmd arg, cmd number +; returns: 0 on success +SENDCMD_TXPKT: + ; first send the command + LOADCP SENDCMD_0 + CALL + + ;LOADCP _RCVBYTE + ;CALL + ;DROP ; remove byte received during transmit + + LOADCP _RCVBYTE ; receive R1 response + CALL + + CBRANCH.NZ SENDCMD_TXPKT_E ; on error we get nonzero + + ; send stuff byte + LOADC $FF + LOADCP _SENDBYTE + CALL + + ; now send data token + LOADCP %11111110 + LOADCP _SENDBYTE + CALL + + ; send data block + ; parameters for _SENDWORDS are on the stack now + LOADCP _SENDWORDS + CALL + + ; send 2 dummy crc bytes + LOADC 0 + LOADCP _SENDBYTE + CALL + LOADC 0 + LOADCP _SENDBYTE + CALL + + ;receive data response byte +SENDCMD_TXPKT_LR: + LOADCP _RCVBYTE + CALL + LOADC $FF ; discard $FF bytes + CMP.S0 NE + CBRANCH SENDCMD_TXPKT_CT + DROP + BRANCH SENDCMD_TXPKT_LR + +SENDCMD_TXPKT_CT: + LOADC $1F + AND ; isolate status bits + LOADC $5 ; command accepted bit set? + CMP NE ; if not, exit with error + CBRANCH SENDCMD_TXPKT_E2 + + ; wait until card is busy +SENDCMD_TXPKT_LB: + LOADCP _RCVBYTE ; receive byte + CALL + CBRANCH.NZ SENDCMD_TXPKT_LB ; loop until byte is 0 + ; wait until card is not busy +SENDCMD_TXPKT_L2: + LOADCP _RCVBYTE ;receive byte + CALL + CBRANCH.Z SENDCMD_TXPKT_L2 ; loop if byte is 0 (i.e. MISO is held low) + + LOADC 0 + BRANCH SENDCMD_TXPKT_X + +SENDCMD_TXPKT_E: + DROP ; remove remaining args + DROP +SENDCMD_TXPKT_E2: + LOADC -1 ; return code for error +SENDCMD_TXPKT_X: + ; terminate command + LOADCP _SPIENDCMD + CALL + + RET + +; send a command and receive a 1-byte-response (R1) +; args: checksum byte, 32-bit cmd arg, cmd number +; returns: received byte +SENDCMD_R1: + LOADCP SENDCMD_0 + CALL + + LOADCP _RCVBYTE + CALL + + ;LOADC 'R' + ;LOADCP CONOUT + ;CALL + + ;terminate command (/cs high, disable clock) + LOADCP _SPIENDCMD + CALL + + RET + +; send a command +; args: checksum byte, 32-bit cmd arg, cmd number +SENDCMD_0: + ; clear RX FIFO first + LOADCP CLEAR_RX_FIFO + CALL + + ;LOADC '>' + ;LOADCP CONOUT + ;CALL + + ; cmd byte is at TOS at this point + LOADC $40 ; or in start of frame bit + OR + LOADCP _SENDBYTE + CALL + ; cmd arg is at TOS now + LOADCP _SENDWORD + CALL + ; checksum byte is at TOS now + LOADCP _SENDBYTE + CALL + + LOADCP _XCVR_ENABLE ; enable transceiver last, + CALL ; a complete command should + RET ; fit into the tx fifo + +; send ACMD and receive a 1-byte-response (R1) +; args: checksum byte, 32-bit cmd arg, ACMD number +; returns: received byte or -1 if first response byte +; indicated an error +SENDACMD_R1: + LOADC $0 + LOADC $0 + LOADC 55 ; send CMD55 + LOADCP SENDCMD_R1 + CALL + + LOADC 1 ; 1 = idle state, no errors + CMP NE + CBRANCH.NZ SENDACMD_ERR + + ; pass our args to SENDCMD_R1 + LOADCP SENDCMD_R1 + CALL + RET + +SENDACMD_ERR: + LOADCP -1 + RET + +; send a command and receive a 4+1-byte-response (R7) +; args: checksum byte, 32-bit cmd arg, cmd number +; returns: received word or -1 if first response byte +; indicated an error + +SENDCMD_R7: + ; send the command + LOADCP SENDCMD_0 + CALL + + ;LOADC '7' + ;LOADCP CONOUT + ;CALL + + LOADCP _RCVBYTE + CALL + + LOADCP _RCVWORD + CALL + + ;terminate command (/cs high, disable clock) + LOADCP _SPIENDCMD + CALL + + SWAP ; swap 1st response byte with received word + LOADC %011111110 ; check for any error flags + AND + CBRANCH.Z SENDCMD_R7_NOERR + DROP + LOADC -1 +SENDCMD_R7_NOERR: + RET + +; send a word as 4 bytes, msb first +_SENDWORD: + DUP ; remember original value for later + + BROT ; rotate msb to lsb (byte 0) + LOADC 255 + AND.S0 ; isolate byte, keep previous value + LOADCP _SENDBYTE + CALL + + BROT ; byte 1 + LOADC 255 + AND.S0 + LOADCP _SENDBYTE + CALL + + BROT ; byte 2 + LOADC 255 + AND + LOADCP _SENDBYTE + CALL + + ; byte 3 is already on the stack + LOADC 255 + AND + LOADCP _SENDBYTE + CALL + + RET + +; send multiple 4-byte-words +; args: number of words, pointer to buffer +_SENDWORDS: + FPADJ -4 + STORE 0 ; store pointer arg into local variable + ; keep counter on stack +_SENDWORDS_LP: + LOAD 0 ; load buf pointer + DUP ; duplicate it + INC 4 ; increment pointer + STORE 0 ; and store it back + LOADI ; load from previously duped pointer + LOADCP _SENDWORD + CALL ; send a word + + DEC 1 ; decrement word counter + DUP + CBRANCH.NZ _SENDWORDS_LP ; if not null, loop + DROP ; remove counter value + + FPADJ 4 + RET + +; receive multiple 4-byte-words and store into +; memory buffer +; args: number of words, pointer to buffer +_RCVWORDS: + FPADJ -4 + STORE 0 ; store pointer arg into local variable + ; keep counter on stack +_RCVWORDS_LP: + LOAD 0 ; load buf pointer for STOREI + LOADCP _RCVWORD + CALL ; receive a word + STOREI 4 ; store to buf with postincrement + STORE 0 ; store pointer variable + + DEC 1 ; decrement word counter + DUP + CBRANCH.NZ _RCVWORDS_LP ; if not null, loop + DROP ; remove counter value + + FPADJ 4 + RET + +; receive 4 bytes, return as word +_RCVWORD: + LOADCP _RCVBYTE ; receive first byte + CALL + BROT ; rotate byte to left + + LOADCP _RCVBYTE ; receive second byte + CALL + OR ; or first and second byte together + BROT ; rotate 1st + 2nd to left + + LOADCP _RCVBYTE ; receive third byte + CALL + OR + BROT + + LOADCP _RCVBYTE ; receive fourth byte + CALL + OR + RET + +_XCVR_ENABLE: + LOADC SPIREG + LOADCP SPI_TX_FLAGS + LOADI + STOREI + DROP + RET + +; send a byte +; args: byte to be sent +_SENDBYTE: + LOADC SPIREG + LOADI ; load spi io register + LOADCP SPI_TX_RDY + AND ; check tx_rdy bit + CBRANCH.Z _SENDBYTE ; if not set, loop + + LOADC SPI_TX_WR ; TX_WR bit + OR ; OR in byte to be send + + LOADC SPIREG + SWAP ; swap value and addr for STOREI + STOREI ; store word (flags + data) to io register + DROP ; remove STOREI result + + RET + +; receive a byte. receiver must be enabled. +; returns: received byte +_RCVBYTE: + LOADC SPIREG + LOADI ; load spi io register + LOADC SPI_RX_AVAIL + AND.S0 ; check rx_avail bit, keep original value + CBRANCH.NZ RECV_GOTIT + DROP ; rx_avail not set, remove register value and loop + BRANCH _RCVBYTE +RECV_GOTIT: + LOADC SPIREG + LOADC SPI_RX_RD ; remove one byte from rx fifo + STOREI + DROP + + LOADC 255 + AND ; keep bits 7-0 + RET + +SPI_TX_FLAGS: .WORD SPI_CTRL_WRITE + SPI_TXRX_EN + SPI_RX_FILTER_EN +SPI_IDLE_FLAGS: .WORD SPI_CTRL_WRITE + + .CPOOL + +CSD_BUF: .BLOCK 4 +CARD_BUF: .BLOCK 128 + diff --git a/lib/stdlib.s b/lib/stdlib.s new file mode 100644 index 0000000..ca5d3ad --- /dev/null +++ b/lib/stdlib.s @@ -0,0 +1,9181 @@ +_NST_STDLIB38ISLEAPYEAR: + FPADJ -12 + LOADREG BP + STORE 4 + DUP + STOREREG BP + STORE 0 + LOAD.B 40 ; NEWYEAR + LOADC 4 + LOADCP _MOD + CALL + LOADC 0 + CMP EQ + LOAD.B 40 ; NEWYEAR + LOADC 100 + LOADCP _MOD + CALL + LOADC 0 + CMP NE + AND + LOAD.B 40 ; NEWYEAR + LOADC 400 + LOADCP _MOD + CALL + LOADC 0 + CMP EQ + OR + STORE 8 ; ISLEAPYEAR + LOAD 8 ; ISLEAPYEAR + LOAD 4 + STOREREG BP + FPADJ 12 + RET +ADVANCETIME: + FPADJ -64 + STORE 4 ; SECONDS + STORE 0 ; D + LOAD 4 ; SECONDS + LOADC 60 + LOADCP _MOD + CALL + STORE 8 ; SECSREST + LOAD 4 ; SECONDS + LOADC 60 + LOADCP _DIV + CALL + STORE 44 ; MINUTESDELTA + LOAD 44 ; MINUTESDELTA + LOADC 60 + LOADCP _MOD + CALL + STORE 12 ; MINUTESREST + LOAD 0 ; D + LOADC 20 + ADD + LOADI + LOAD 8 ; SECSREST + ADD + STORE 20 ; NEWSECS + LOAD 20 ; NEWSECS + LOADC 60 + CMP GE + .LCBRANCHZ _IF_ELSE0_STDLIB + LOAD 20 ; NEWSECS + LOADC 60 + SUB + STORE 20 ; NEWSECS + LOAD 44 ; MINUTESDELTA + LOADC 1 + ADD + STORE 44 ; MINUTESDELTA + LOAD 12 ; MINUTESREST + LOADC 1 + ADD + STORE 12 ; MINUTESREST +_IF_ELSE0_STDLIB: +_IF_END0_STDLIB: + LOAD 0 ; D + LOADC 20 + ADD + LOAD 20 ; NEWSECS + DUP + LOADC 0 + LOADC 59 + LOADCP _RANGECHECK + CALL + STOREI + DROP + LOAD 44 ; MINUTESDELTA + LOADC 60 + LOADCP _DIV + CALL + STORE 48 ; HOURSDELTA + LOAD 48 ; HOURSDELTA + LOADC 24 + LOADCP _MOD + CALL + STORE 16 ; HOURSREST + LOAD 0 ; D + LOADC 16 + ADD + LOADI + LOAD 12 ; MINUTESREST + ADD + STORE 24 ; NEWMINUTES + LOAD 24 ; NEWMINUTES + LOADC 60 + CMP GE + .LCBRANCHZ _IF_ELSE1_STDLIB + LOAD 24 ; NEWMINUTES + LOADC 60 + SUB + STORE 24 ; NEWMINUTES + LOAD 48 ; HOURSDELTA + LOADC 1 + ADD + STORE 48 ; HOURSDELTA + LOAD 16 ; HOURSREST + LOADC 1 + ADD + STORE 16 ; HOURSREST +_IF_ELSE1_STDLIB: +_IF_END1_STDLIB: + LOAD 0 ; D + LOADC 16 + ADD + LOAD 24 ; NEWMINUTES + DUP + LOADC 0 + LOADC 59 + LOADCP _RANGECHECK + CALL + STOREI + DROP + LOAD 48 ; HOURSDELTA + LOADC 24 + LOADCP _DIV + CALL + STORE 52 ; DAYSDELTA + LOAD 0 ; D + INC 12 + LOADI + LOAD 16 ; HOURSREST + ADD + STORE 28 ; NEWHOURS + LOAD 28 ; NEWHOURS + LOADC 24 + CMP GE + .LCBRANCHZ _IF_ELSE2_STDLIB + LOAD 28 ; NEWHOURS + LOADC 24 + SUB + STORE 28 ; NEWHOURS + LOAD 52 ; DAYSDELTA + LOADC 1 + ADD + STORE 52 ; DAYSDELTA +_IF_ELSE2_STDLIB: +_IF_END2_STDLIB: + LOAD 0 ; D + INC 12 + LOAD 28 ; NEWHOURS + DUP + LOADC 0 + LOADC 23 + LOADCP _RANGECHECK + CALL + STOREI + DROP + LOAD 0 ; D + INC 8 + LOADI + LOAD 52 ; DAYSDELTA + ADD + STORE 32 ; NEWDAYS + LOAD 0 ; D + INC 4 + LOADI + STORE 36 ; NEWMONTH + LOAD 0 ; D + LOADI + STORE 40 ; NEWYEAR + LOADREG FP + LOADCP _NST_STDLIB38ISLEAPYEAR + CALL + .LCBRANCHZ _IF_ELSE3_STDLIB + LOADC 1 + STORE 56 ; MPDINDEX + .LBRANCH _IF_END3_STDLIB +_IF_ELSE3_STDLIB: + LOADC 0 + STORE 56 ; MPDINDEX +_IF_END3_STDLIB: + LOADCP DATETIMEMTAB ; DATETIMEMTAB + LOAD 56 ; MPDINDEX + DUP + LOADC 2 + LOADCP _BOUNDSCHECK + CALL + LOADC 48 + LOADCP _MULU + CALL + ADD + LOAD 36 ; NEWMONTH + DEC 1 + DUP + LOADC 12 + LOADCP _BOUNDSCHECK + CALL + SHL 2 + ADD + LOADI + STORE 60 ; DAYSPERMONTH +_WHILE_START0_STDLIB: + LOAD 32 ; NEWDAYS + LOAD 60 ; DAYSPERMONTH + CMP GT + .LCBRANCHZ _WHILE_END0_STDLIB + LOAD 36 ; NEWMONTH + LOADC 1 + ADD + STORE 36 ; NEWMONTH + LOAD 32 ; NEWDAYS + LOAD 60 ; DAYSPERMONTH + SUB + STORE 32 ; NEWDAYS + LOAD 36 ; NEWMONTH + LOADC 12 + CMP GT + .LCBRANCHZ _IF_ELSE4_STDLIB + LOAD 40 ; NEWYEAR + LOADC 1 + ADD + STORE 40 ; NEWYEAR + LOADC 1 + STORE 36 ; NEWMONTH + LOADREG FP + LOADCP _NST_STDLIB38ISLEAPYEAR + CALL + .LCBRANCHZ _IF_ELSE5_STDLIB + LOADC 1 + STORE 56 ; MPDINDEX + .LBRANCH _IF_END5_STDLIB + .CPOOL +_IF_ELSE5_STDLIB: + LOADC 0 + STORE 56 ; MPDINDEX +_IF_END5_STDLIB: +_IF_ELSE4_STDLIB: +_IF_END4_STDLIB: + LOADCP DATETIMEMTAB ; DATETIMEMTAB + LOAD 56 ; MPDINDEX + DUP + LOADC 2 + LOADCP _BOUNDSCHECK + CALL + LOADC 48 + LOADCP _MULU + CALL + ADD + LOAD 36 ; NEWMONTH + DEC 1 + DUP + LOADC 12 + LOADCP _BOUNDSCHECK + CALL + SHL 2 + ADD + LOADI + STORE 60 ; DAYSPERMONTH + .LBRANCH _WHILE_START0_STDLIB +_WHILE_END0_STDLIB: + LOAD 0 ; D + INC 8 + LOAD 32 ; NEWDAYS + DUP + LOADC 1 + LOADC 31 + LOADCP _RANGECHECK + CALL + STOREI + DROP + LOAD 0 ; D + INC 4 + LOAD 36 ; NEWMONTH + DUP + LOADC 1 + LOADC 12 + LOADCP _RANGECHECK + CALL + STOREI + DROP + LOAD 0 ; D + LOAD 40 ; NEWYEAR + STOREI + DROP + FPADJ 64 + RET +GETTIME: + FPADJ -16 + STORE 0 ; GETTIME + LOADCP SYSCLOCK ; SYSCLOCK + LOADI + LOADC 0 + CMP EQ + .LCBRANCHZ _IF_ELSE6_STDLIB + LOADCP SYSCLOCK ; SYSCLOCK + LOADC 2001 + STOREI + DROP + LOADCP SYSCLOCK,4 ; SYSCLOCK + LOADC 1 + DUP + LOADC 1 + LOADC 12 + LOADCP _RANGECHECK + CALL + STOREI + DROP + LOADCP SYSCLOCK,8 ; SYSCLOCK + LOADC 1 + DUP + LOADC 1 + LOADC 31 + LOADCP _RANGECHECK + CALL + STOREI + DROP +_IF_ELSE6_STDLIB: +_IF_END6_STDLIB: + LOADCP GETTICKS + CALL + STORE 4 ; NOW + LOAD 4 ; NOW + LOADCP SYSLASTTICKS ; SYSLASTTICKS + LOADI + SUB + STORE 8 ; DELTA + LOADCP SYSLASTTICKS ; SYSLASTTICKS + LOAD 4 ; NOW + STOREI + DROP + LOAD 8 ; DELTA + LOADC 20 + LOADCP _DIV + CALL + STORE 12 ; SECS + LOADCP SYSCLOCK ; SYSCLOCK + LOAD 12 ; SECS + LOADCP ADVANCETIME + CALL + LOAD 0 ; GETTIME + LOADCP SYSCLOCK ; SYSCLOCK + LOADC 6 + LOADCP _COPYWORDS + CALL + LOAD 0 ; GETTIME + FPADJ 16 + RET +TIMESTR: + FPADJ -44 + STORE 28 ; TIMESTR + STORE 24 ; SHOWSECONDS + ; D + LOADREG FP + SWAP + LOADC 6 + LOADCP _COPYWORDS + CALL + LOADC 4 + ; DIGITS + LOADREG FP + LOADC 32 + ADD + LOADCP _INITSTRINGF + CALL + LOAD 12 ; D + LOADC 0 + ; DIGITS + LOADREG FP + LOADC 32 + ADD + LOADCP INTSTR + CALL + LOAD 12 ; D + LOADC 10 + CMP LT + .LCBRANCHZ _IF_ELSE7_STDLIB + LOAD 28 ; TIMESTR + LOADCP _C_S_0_STDLIB + LOADCP _COPYSTRING + CALL +_IF_ELSE7_STDLIB: +_IF_END7_STDLIB: + LOAD 28 ; TIMESTR + LOAD 28 ; TIMESTR + LOADREG FP + LOADC 88 + SUB + SWAP + LOADC 80 + FPADJ -88 + LOADCP _INITSTRINGFROM + CALL + FPADJ 88 + LOADREG FP + LOADC 88 + SUB + ; DIGITS + LOADREG FP + LOADC 32 + ADD + FPADJ -88 + LOADCP _APPENDSTRING + CALL + FPADJ 88 + LOADREG FP + LOADC 88 + SUB + LOADCP _C_S_1_STDLIB + FPADJ -88 + LOADCP _APPENDSTRING + CALL + FPADJ 88 + LOADREG FP + LOADC 88 + SUB + FPADJ -88 + LOADCP _COPYSTRING + CALL + FPADJ 88 + LOAD 16 ; D + LOADC 0 + ; DIGITS + LOADREG FP + LOADC 32 + ADD + LOADCP INTSTR + CALL + LOAD 16 ; D + LOADC 10 + CMP LT + .LCBRANCHZ _IF_ELSE8_STDLIB + LOAD 28 ; TIMESTR + LOADC 48 + LOADCP APPENDCHAR + CALL +_IF_ELSE8_STDLIB: +_IF_END8_STDLIB: + LOAD 28 ; TIMESTR + LOAD 28 ; TIMESTR + LOADREG FP + LOADC 88 + SUB + SWAP + LOADC 80 + FPADJ -88 + LOADCP _INITSTRINGFROM + CALL + FPADJ 88 + LOADREG FP + LOADC 88 + SUB + ; DIGITS + LOADREG FP + LOADC 32 + ADD + FPADJ -88 + LOADCP _APPENDSTRING + CALL + FPADJ 88 + LOADREG FP + LOADC 88 + SUB + FPADJ -88 + LOADCP _COPYSTRING + CALL + FPADJ 88 + LOAD 24 ; SHOWSECONDS + .LCBRANCHZ _IF_ELSE9_STDLIB + LOAD 28 ; TIMESTR + LOADC 58 + LOADCP APPENDCHAR + CALL + LOAD 20 ; D + LOADC 0 + ; DIGITS + LOADREG FP + LOADC 32 + ADD + LOADCP INTSTR + CALL + LOAD 20 ; D + LOADC 10 + CMP LT + .LCBRANCHZ _IF_ELSE10_STDLIB + LOAD 28 ; TIMESTR + LOADC 48 + LOADCP APPENDCHAR + CALL +_IF_ELSE10_STDLIB: +_IF_END10_STDLIB: + LOAD 28 ; TIMESTR + LOAD 28 ; TIMESTR + LOADREG FP + LOADC 88 + SUB + SWAP + LOADC 80 + FPADJ -88 + LOADCP _INITSTRINGFROM + CALL + FPADJ 88 + LOADREG FP + LOADC 88 + SUB + ; DIGITS + LOADREG FP + LOADC 32 + ADD + FPADJ -88 + LOADCP _APPENDSTRING + CALL + FPADJ 88 + LOADREG FP + LOADC 88 + SUB + FPADJ -88 + LOADCP _COPYSTRING + CALL + FPADJ 88 +_IF_ELSE9_STDLIB: +_IF_END9_STDLIB: + LOAD 28 ; TIMESTR + FPADJ 44 + RET + .CPOOL +DATESTR: + FPADJ -40 + STORE 24 ; DATESTR + ; D + LOADREG FP + SWAP + LOADC 6 + LOADCP _COPYWORDS + CALL + LOADC 4 + ; DIGITS + LOADREG FP + LOADC 28 + ADD + LOADCP _INITSTRINGF + CALL + LOAD 0 ; D + LOADC 0 + ; DIGITS + LOADREG FP + LOADC 28 + ADD + LOADCP INTSTR + CALL + LOAD 24 ; DATESTR + LOAD 24 ; DATESTR + LOADREG FP + LOADC 88 + SUB + SWAP + LOADC 80 + FPADJ -88 + LOADCP _INITSTRINGFROM + CALL + FPADJ 88 + LOADREG FP + LOADC 88 + SUB + ; DIGITS + LOADREG FP + LOADC 28 + ADD + FPADJ -88 + LOADCP _APPENDSTRING + CALL + FPADJ 88 + LOADREG FP + LOADC 88 + SUB + LOADCP _C_S_2_STDLIB + FPADJ -88 + LOADCP _APPENDSTRING + CALL + FPADJ 88 + LOADREG FP + LOADC 88 + SUB + FPADJ -88 + LOADCP _COPYSTRING + CALL + FPADJ 88 + LOAD 4 ; D + LOADC 0 + ; DIGITS + LOADREG FP + LOADC 28 + ADD + LOADCP INTSTR + CALL + LOAD 4 ; D + LOADC 10 + CMP LT + .LCBRANCHZ _IF_ELSE11_STDLIB + LOAD 24 ; DATESTR + LOADC 48 + LOADCP APPENDCHAR + CALL +_IF_ELSE11_STDLIB: +_IF_END11_STDLIB: + LOAD 24 ; DATESTR + LOAD 24 ; DATESTR + LOADREG FP + LOADC 88 + SUB + SWAP + LOADC 80 + FPADJ -88 + LOADCP _INITSTRINGFROM + CALL + FPADJ 88 + LOADREG FP + LOADC 88 + SUB + ; DIGITS + LOADREG FP + LOADC 28 + ADD + FPADJ -88 + LOADCP _APPENDSTRING + CALL + FPADJ 88 + LOADREG FP + LOADC 88 + SUB + FPADJ -88 + LOADCP _COPYSTRING + CALL + FPADJ 88 + LOAD 24 ; DATESTR + LOADC 45 + LOADCP APPENDCHAR + CALL + LOAD 8 ; D + LOADC 0 + ; DIGITS + LOADREG FP + LOADC 28 + ADD + LOADCP INTSTR + CALL + LOAD 8 ; D + LOADC 10 + CMP LT + .LCBRANCHZ _IF_ELSE12_STDLIB + LOAD 24 ; DATESTR + LOADC 48 + LOADCP APPENDCHAR + CALL +_IF_ELSE12_STDLIB: +_IF_END12_STDLIB: + LOAD 24 ; DATESTR + LOAD 24 ; DATESTR + LOADREG FP + LOADC 88 + SUB + SWAP + LOADC 80 + FPADJ -88 + LOADCP _INITSTRINGFROM + CALL + FPADJ 88 + LOADREG FP + LOADC 88 + SUB + ; DIGITS + LOADREG FP + LOADC 28 + ADD + FPADJ -88 + LOADCP _APPENDSTRING + CALL + FPADJ 88 + LOADREG FP + LOADC 88 + SUB + FPADJ -88 + LOADCP _COPYSTRING + CALL + FPADJ 88 + LOAD 24 ; DATESTR + FPADJ 40 + RET +GETTIMESTAMP: + FPADJ -12 + STORE 0 ; D + LOAD 0 ; D + LOADI + LOADC 1970 + SUB + LOADC 24 + LOADCP _SHLM + CALL + STORE 8 ; I + LOAD 8 ; I + LOAD 0 ; D + INC 4 + LOADI + LOADC 20 + LOADCP _SHLM + CALL + OR + STORE 8 ; I + LOAD 8 ; I + LOAD 0 ; D + INC 8 + LOADI + LOADC 15 + LOADCP _SHLM + CALL + OR + STORE 8 ; I + LOAD 8 ; I + LOAD 0 ; D + INC 12 + LOADI + LOADC 10 + LOADCP _SHLM + CALL + OR + STORE 8 ; I + LOAD 8 ; I + LOAD 0 ; D + LOADC 16 + ADD + LOADI + LOADC 4 + LOADCP _SHLM + CALL + OR + STORE 8 ; I + LOAD 8 ; I + LOAD 0 ; D + LOADC 20 + ADD + LOADI + LOADC 2 + LOADCP _SHRM + CALL + OR + STORE 8 ; I + LOAD 8 ; I + STORE 4 ; GETTIMESTAMP + LOAD 4 ; GETTIMESTAMP + FPADJ 12 + RET +GETDATETIME: + FPADJ -8 + STORE 4 ; GETDATETIME + STORE 0 ; TS + LOAD 4 ; GETDATETIME + LOADC 20 + ADD + LOAD 0 ; TS + LOADC 15 + AND + LOADC 2 + LOADCP _SHLM + CALL + DUP + LOADC 0 + LOADC 59 + LOADCP _RANGECHECK + CALL + STOREI + DROP + LOAD 0 ; TS + LOADC 4 + LOADCP _SHRM + CALL + STORE 0 ; TS + LOAD 4 ; GETDATETIME + LOADC 16 + ADD + LOAD 0 ; TS + LOADC 63 + AND + DUP + LOADC 0 + LOADC 59 + LOADCP _RANGECHECK + CALL + STOREI + DROP + LOAD 0 ; TS + LOADC 6 + LOADCP _SHRM + CALL + STORE 0 ; TS + LOAD 4 ; GETDATETIME + INC 12 + LOAD 0 ; TS + LOADC 31 + AND + DUP + LOADC 0 + LOADC 23 + LOADCP _RANGECHECK + CALL + STOREI + DROP + LOAD 0 ; TS + LOADC 5 + LOADCP _SHRM + CALL + STORE 0 ; TS + LOAD 4 ; GETDATETIME + INC 8 + LOAD 0 ; TS + LOADC 31 + AND + DUP + LOADC 1 + LOADC 31 + LOADCP _RANGECHECK + CALL + STOREI + DROP + LOAD 0 ; TS + LOADC 5 + LOADCP _SHRM + CALL + STORE 0 ; TS + LOAD 4 ; GETDATETIME + INC 4 + LOAD 0 ; TS + LOADC 15 + AND + DUP + LOADC 1 + LOADC 12 + LOADCP _RANGECHECK + CALL + STOREI + DROP + LOAD 0 ; TS + LOADC 4 + LOADCP _SHRM + CALL + STORE 0 ; TS + LOAD 4 ; GETDATETIME + LOADC 1970 + LOAD 0 ; TS + LOADC 255 + AND + ADD + STOREI + DROP + LOAD 4 ; GETDATETIME + FPADJ 8 + RET + .CPOOL +GETCURTIMESTAMP: + FPADJ -28 + ; NOW + LOADREG FP + INC 4 + LOADREG FP + LOADC 24 + SUB + FPADJ -24 + LOADCP GETTIME + CALL + FPADJ 24 + LOADC 6 + FPADJ -24 + LOADCP _COPYWORDS + CALL + FPADJ 24 + ; NOW + LOADREG FP + INC 4 + LOADCP GETTIMESTAMP + CALL + STORE 0 ; GETCURTIMESTAMP + LOAD 0 ; GETCURTIMESTAMP + FPADJ 28 + RET +COPY: + FPADJ -104 + STORE 96 ; COPY + STORE 92 ; COUNT + STORE 88 ; INDEX + ; S + LOADREG FP + SWAP + LOADC 80 + LOADCP _INITSTRINGFROM + CALL + LOAD 96 ; COPY + LOADCP _C_S_3_STDLIB + LOADCP _COPYSTRING + CALL + ; S + LOADREG FP + LOADCP LENGTH + CALL + STORE 100 ; LEN + LOAD 88 ; INDEX + LOADC 1 + CMP LT + .LCBRANCHZ _IF_ELSE13_STDLIB + LOADC 1 + STORE 88 ; INDEX +_IF_ELSE13_STDLIB: +_IF_END13_STDLIB: +_WHILE_START1_STDLIB: + LOAD 92 ; COUNT + LOADC 0 + CMP GT + LOAD 88 ; INDEX + LOAD 100 ; LEN + CMP LE + AND + .LCBRANCHZ _WHILE_END1_STDLIB + LOAD 96 ; COPY + LOAD 96 ; COPY + LOADREG FP + LOADC 88 + SUB + SWAP + LOADC 80 + FPADJ -88 + LOADCP _INITSTRINGFROM + CALL + FPADJ 88 + LOADREG FP + LOADC 88 + SUB + ; S + LOADREG FP + LOAD 88 ; INDEX + LOADCP _INDEXSTRING + CALL + LOADI.S1.X2Y + BSEL + LOADREG FP + LOADC 100 + SUB + SWAP + OVER + LOADCP _CHARTOSTRING + CALL + FPADJ -100 + LOADCP _APPENDSTRING + CALL + FPADJ 100 + LOADREG FP + LOADC 88 + SUB + FPADJ -100 + LOADCP _COPYSTRING + CALL + FPADJ 100 + LOAD 88 ; INDEX + LOADC 1 + ADD + STORE 88 ; INDEX + LOAD 92 ; COUNT + LOADC 1 + SUB + STORE 92 ; COUNT + .LBRANCH _WHILE_START1_STDLIB +_WHILE_END1_STDLIB: + LOAD 96 ; COPY + FPADJ 104 + RET +INSERT: + FPADJ -112 + STORE 92 ; POSITION + STORE 88 ; DEST + ; INS + LOADREG FP + SWAP + LOADC 80 + LOADCP _INITSTRINGFROM + CALL + LOAD 92 ; POSITION + LOADC 1 + CMP LT + .LCBRANCHZ _IF_ELSE14_STDLIB + LOADC 1 + STORE 92 ; POSITION +_IF_ELSE14_STDLIB: +_IF_END14_STDLIB: + LOAD 92 ; POSITION + LOAD 88 ; DEST + LOADCP LENGTH + CALL + LOADC 1 + ADD + CMP GT + .LCBRANCHZ _IF_ELSE15_STDLIB + LOAD 88 ; DEST + LOADCP LENGTH + CALL + LOADC 1 + ADD + STORE 92 ; POSITION +_IF_ELSE15_STDLIB: +_IF_END15_STDLIB: + LOAD 88 ; DEST + LOADCP LENGTH + CALL + STORE 104 ; FROM + LOAD 88 ; DEST + LOADCP LENGTH + CALL + LOAD 92 ; POSITION + SUB + LOADC 1 + ADD + STORE 100 ; COUNT + LOAD 104 ; FROM + ; INS + LOADREG FP + LOADCP LENGTH + CALL + ADD + STORE 108 ; TO_ + LOAD 88 ; DEST + LOAD 88 ; DEST + LOADCP LENGTH + CALL + ; INS + LOADREG FP + LOADCP LENGTH + CALL + ADD + LOADCP _SETSTRINGLENGTH + CALL + LOADC 1 + STORE 96 ; I + LOAD 100 ; COUNT +_FOR_START0_STDLIB: + LOAD 96 ; I + OVER + CMP GT + .LCBRANCH _FOR_END0_STDLIB + LOAD 108 ; TO_ + LOAD 88 ; DEST + LOADCP MAXLENGTH + CALL + CMP LE + .LCBRANCHZ _IF_ELSE16_STDLIB + LOAD 88 ; DEST + LOAD 108 ; TO_ + LOADCP _INDEXSTRING + CALL + LOAD 88 ; DEST + LOAD 104 ; FROM + LOADCP _INDEXSTRING + CALL + LOADI.S1.X2Y + BSEL + LOADCP _SETSTRINGCHAR + CALL + LOAD 108 ; TO_ + LOADC 1 + SUB + STORE 108 ; TO_ + LOAD 104 ; FROM + LOADC 1 + SUB + STORE 104 ; FROM +_IF_ELSE16_STDLIB: +_IF_END16_STDLIB: + LOAD 96 ; I + INC 1 + STORE 96 ; I + .LBRANCH _FOR_START0_STDLIB +_FOR_END0_STDLIB: + DROP + LOAD 92 ; POSITION + STORE 108 ; TO_ + ; INS + LOADREG FP + LOADCP LENGTH + CALL + STORE 100 ; COUNT + LOADC 1 + STORE 96 ; I + LOAD 100 ; COUNT +_FOR_START1_STDLIB: + LOAD 96 ; I + OVER + CMP GT + .LCBRANCH _FOR_END1_STDLIB + LOAD 108 ; TO_ + LOAD 88 ; DEST + LOADCP MAXLENGTH + CALL + CMP LE + .LCBRANCHZ _IF_ELSE17_STDLIB + LOAD 88 ; DEST + LOAD 108 ; TO_ + LOADCP _INDEXSTRING + CALL + ; INS + LOADREG FP + LOAD 96 ; I + LOADCP _INDEXSTRING + CALL + LOADI.S1.X2Y + BSEL + LOADCP _SETSTRINGCHAR + CALL + LOAD 108 ; TO_ + LOADC 1 + ADD + STORE 108 ; TO_ +_IF_ELSE17_STDLIB: +_IF_END17_STDLIB: + LOAD 96 ; I + INC 1 + STORE 96 ; I + .LBRANCH _FOR_START1_STDLIB + .CPOOL +_FOR_END1_STDLIB: + DROP + FPADJ 112 + RET +DELETE: + FPADJ -24 + STORE 8 ; COUNT + STORE 4 ; FROM + STORE 0 ; S + LOAD 0 ; S + LOADCP LENGTH + CALL + STORE 16 ; LEN + LOAD 4 ; FROM + LOADC 0 + CMP GT + LOAD 4 ; FROM + LOAD 16 ; LEN + CMP LE + AND + LOAD 8 ; COUNT + LOADC 0 + CMP GT + AND + .LCBRANCHZ _IF_ELSE18_STDLIB + LOAD 4 ; FROM + LOAD 8 ; COUNT + ADD + LOAD 16 ; LEN + CMP LE + .LCBRANCHZ _IF_ELSE19_STDLIB + LOAD 16 ; LEN + LOAD 8 ; COUNT + SUB + STORE 20 ; LAST + LOAD 4 ; FROM + STORE 12 ; I + LOAD 20 ; LAST +_FOR_START2_STDLIB: + LOAD 12 ; I + OVER + CMP GT + .LCBRANCH _FOR_END2_STDLIB + LOAD 0 ; S + LOAD 12 ; I + LOADCP _INDEXSTRING + CALL + LOAD 0 ; S + LOAD 12 ; I + LOAD 8 ; COUNT + ADD + LOADCP _INDEXSTRING + CALL + LOADI.S1.X2Y + BSEL + LOADCP _SETSTRINGCHAR + CALL + LOAD 12 ; I + INC 1 + STORE 12 ; I + .LBRANCH _FOR_START2_STDLIB +_FOR_END2_STDLIB: + DROP + .LBRANCH _IF_END19_STDLIB +_IF_ELSE19_STDLIB: + LOAD 4 ; FROM + LOADC 1 + SUB + STORE 20 ; LAST +_IF_END19_STDLIB: + LOAD 0 ; S + LOAD 20 ; LAST + LOADCP _SETSTRINGLENGTH + CALL +_IF_ELSE18_STDLIB: +_IF_END18_STDLIB: + FPADJ 24 + RET +POS: + FPADJ -124 + STORE 88 ; S + ; SUBSTR + LOADREG FP + SWAP + LOADC 80 + LOADCP _INITSTRINGFROM + CALL + LOADC 0 + STORE 116 ; FOUND + ; SUBSTR + LOADREG FP + LOADCP LENGTH + CALL + STORE 96 ; SUBSTRLEN + LOAD 88 ; S + LOADCP LENGTH + CALL + STORE 100 ; SLEN + LOADC 1 + STORE 104 ; SEARCHPOS + LOADC 1 + STORE 112 ; SUBPOS + LOAD 96 ; SUBSTRLEN + LOADC 0 + CMP GT + LOAD 100 ; SLEN + LOADC 0 + CMP GT + AND + .LCBRANCHZ _IF_ELSE20_STDLIB +_WHILE_START2_STDLIB: + LOAD 116 ; FOUND + LOADC 0 + CMP EQ + LOAD 104 ; SEARCHPOS + LOAD 100 ; SLEN + CMP LE + AND + .LCBRANCHZ _WHILE_END2_STDLIB + ; SUBSTR + LOADREG FP + LOAD 112 ; SUBPOS + LOADCP _INDEXSTRING + CALL + LOADI.S1.X2Y + BSEL + LOAD 88 ; S + LOAD 104 ; SEARCHPOS + LOADCP _INDEXSTRING + CALL + LOADI.S1.X2Y + BSEL + CMP NE + .LCBRANCHZ _IF_ELSE21_STDLIB + LOAD 112 ; SUBPOS + LOADC 1 + CMP EQ + .LCBRANCHZ _IF_ELSE22_STDLIB + LOAD 104 ; SEARCHPOS + LOADC 1 + ADD + STORE 104 ; SEARCHPOS +_IF_ELSE22_STDLIB: +_IF_END22_STDLIB: + LOADC 1 + STORE 112 ; SUBPOS + .LBRANCH _IF_END21_STDLIB +_IF_ELSE21_STDLIB: + LOAD 112 ; SUBPOS + LOADC 1 + CMP EQ + .LCBRANCHZ _IF_ELSE23_STDLIB + LOAD 104 ; SEARCHPOS + STORE 92 ; POS +_IF_ELSE23_STDLIB: +_IF_END23_STDLIB: + LOAD 112 ; SUBPOS + LOAD 96 ; SUBSTRLEN + CMP EQ + .LCBRANCHZ _IF_ELSE24_STDLIB + LOADC 1 + STORE 116 ; FOUND + .LBRANCH _IF_END24_STDLIB +_IF_ELSE24_STDLIB: + LOAD 112 ; SUBPOS + LOADC 1 + ADD + STORE 112 ; SUBPOS + LOAD 104 ; SEARCHPOS + LOADC 1 + ADD + STORE 104 ; SEARCHPOS +_IF_END24_STDLIB: +_IF_END21_STDLIB: + .LBRANCH _WHILE_START2_STDLIB +_WHILE_END2_STDLIB: +_IF_ELSE20_STDLIB: +_IF_END20_STDLIB: + LOAD 116 ; FOUND + LOADC 0 + CMP EQ + .LCBRANCHZ _IF_ELSE25_STDLIB + LOADC 0 + STORE 92 ; POS +_IF_ELSE25_STDLIB: +_IF_END25_STDLIB: + LOAD 92 ; POS + FPADJ 124 + RET +PWROFTEN: + FPADJ -20 + STORE 0 ; EXP + LOAD 0 ; EXP + LOADC 0 + CMP EQ + .LCBRANCHZ _IF_ELSE26_STDLIB + LOADC 1 + LOADCP _INTTOFLOAT32 + CALL + STORE 12 ; RES + .LBRANCH _IF_END26_STDLIB + .CPOOL +_IF_ELSE26_STDLIB: + LOAD 0 ; EXP + LOADC 1 + CMP EQ + .LCBRANCHZ _IF_ELSE27_STDLIB + LOADC 10 + LOADCP _INTTOFLOAT32 + CALL + STORE 12 ; RES + .LBRANCH _IF_END27_STDLIB +_IF_ELSE27_STDLIB: + LOADC 1 + STORE 16 ; SOFAR + LOADC 10 + LOADCP _INTTOFLOAT32 + CALL + STORE 12 ; RES +_WHILE_START3_STDLIB: + LOAD 16 ; SOFAR + LOADC 1 + LOADCP _SHLM + CALL + LOAD 0 ; EXP + CMP LE + .LCBRANCHZ _WHILE_END3_STDLIB + LOAD 12 ; RES + LOAD 12 ; RES + LOADCP _MULFLOAT32 + CALL + STORE 12 ; RES + LOAD 16 ; SOFAR + LOADC 1 + LOADCP _SHLM + CALL + STORE 16 ; SOFAR + .LBRANCH _WHILE_START3_STDLIB +_WHILE_END3_STDLIB: + LOAD 16 ; SOFAR + LOADC 1 + ADD + STORE 8 ; I + LOAD 0 ; EXP +_FOR_START3_STDLIB: + LOAD 8 ; I + OVER + CMP GT + .LCBRANCH _FOR_END3_STDLIB + LOAD 12 ; RES + LOADC 10 + LOADCP _INTTOFLOAT32 + CALL + LOADCP _MULFLOAT32 + CALL + STORE 12 ; RES + LOAD 8 ; I + INC 1 + STORE 8 ; I + .LBRANCH _FOR_START3_STDLIB +_FOR_END3_STDLIB: + DROP +_IF_END27_STDLIB: +_IF_END26_STDLIB: + LOAD 12 ; RES + STORE 4 ; PWROFTEN + LOAD 4 ; PWROFTEN + FPADJ 20 + RET +EXP: + FPADJ -28 + STORE 0 ; EXPONENT + LOAD 0 ; EXPONENT + STORE 8 ; X + LOAD 8 ; X + STORE 16 ; FRC + LOADCP 1073741951 + LOAD 8 ; X + LOADCP _ADDFLOAT32 + CALL + STORE 12 ; P + LOADCP 1073741951 + STORE 20 ; I +_REPEAT_START0_STDLIB: + LOAD 20 ; I + LOADCP 1073741951 + LOADCP _ADDFLOAT32 + CALL + STORE 20 ; I + LOAD 16 ; FRC + LOAD 8 ; X + LOAD 20 ; I + LOADCP _DIVFLOAT32 + CALL + LOADCP _MULFLOAT32 + CALL + STORE 16 ; FRC + LOAD 12 ; P + STORE 24 ; L + LOAD 12 ; P + LOAD 16 ; FRC + LOADCP _ADDFLOAT32 + CALL + STORE 12 ; P + LOAD 24 ; L + LOAD 12 ; P + LOADCP _CMPFLOAT32 + CALL + LOADC 0 + CMP EQ + .LCBRANCHZ _REPEAT_START0_STDLIB +_REPEAT_END0_STDLIB: + LOAD 12 ; P + STORE 4 ; EXP + LOAD 4 ; EXP + FPADJ 28 + RET +LN: + FPADJ -36 + STORE 0 ; N + LOADC 0 + STORE 8 ; A + LOAD 0 ; N + LOADC 0 + LOADCP _INTTOFLOAT32 + CALL + LOADCP _CMPFLOAT32 + CALL + LOADC 0 + CMP GT + .LCBRANCHZ _IF_ELSE28_STDLIB + LOAD 0 ; N + LOADCP 1459366528 + LOADCP _DIVFLOAT32 + CALL + STORE 20 ; D +_WHILE_START4_STDLIB: + LOAD 20 ; D + LOADCP 1073741951 + LOADCP _CMPFLOAT32 + CALL + LOADC 0 + CMP GT + .LCBRANCHZ _WHILE_END4_STDLIB + LOAD 8 ; A + LOADC 1 + ADD + STORE 8 ; A + LOAD 20 ; D + STORE 0 ; N + LOAD 0 ; N + LOADCP 1459366528 + LOADCP _DIVFLOAT32 + CALL + STORE 20 ; D + .LBRANCH _WHILE_START4_STDLIB +_WHILE_END4_STDLIB: + LOAD 0 ; N + LOADCP 1459366528 + LOADCP _MULFLOAT32 + CALL + STORE 20 ; D +_WHILE_START5_STDLIB: + LOAD 20 ; D + LOADCP 1073741951 + LOADCP _CMPFLOAT32 + CALL + LOADC 0 + CMP LT + .LCBRANCHZ _WHILE_END5_STDLIB + LOAD 8 ; A + LOADC 1 + SUB + STORE 8 ; A + LOAD 20 ; D + STORE 0 ; N + LOAD 0 ; N + LOADCP 1459366528 + LOADCP _MULFLOAT32 + CALL + STORE 20 ; D + .LBRANCH _WHILE_START5_STDLIB +_WHILE_END5_STDLIB: + LOADCP 1073741951 + LOAD 0 ; N + LOADC 1 + LOADCP _INTTOFLOAT32 + CALL + LOADCP _SUBFLOAT32 + CALL + LOADCP _DIVFLOAT32 + CALL + STORE 20 ; D + LOAD 20 ; D + LOAD 20 ; D + LOADCP _ADDFLOAT32 + CALL + LOADCP 1073741951 + LOADCP _ADDFLOAT32 + CALL + STORE 20 ; D + LOAD 20 ; D + LOAD 20 ; D + LOADCP _MULFLOAT32 + CALL + STORE 24 ; E + LOADC 0 + LOADCP _INTTOFLOAT32 + CALL + STORE 16 ; C + LOADC 1 + STORE 12 ; B + LOADCP 1073741951 + STORE 28 ; F + LOAD 16 ; C + LOADCP 1073741951 + LOAD 12 ; B + LOAD 28 ; F + SWAP + LOADCP _INTTOFLOAT32 + CALL + SWAP + LOADCP _MULFLOAT32 + CALL + LOADCP _DIVFLOAT32 + CALL + LOADCP _ADDFLOAT32 + CALL + STORE 32 ; CN +_WHILE_START6_STDLIB: + LOAD 16 ; C + LOADCP 1407374958 + LOADCP _ADDFLOAT32 + CALL + LOAD 32 ; CN + LOADCP _CMPFLOAT32 + CALL + LOADC 0 + CMP LT + .LCBRANCHZ _WHILE_END6_STDLIB + LOAD 32 ; CN + STORE 16 ; C + LOAD 12 ; B + LOADC 2 + ADD + STORE 12 ; B + LOAD 28 ; F + LOAD 24 ; E + LOADCP _MULFLOAT32 + CALL + STORE 28 ; F + LOAD 16 ; C + LOADCP 1073741951 + LOAD 12 ; B + LOAD 28 ; F + SWAP + LOADCP _INTTOFLOAT32 + CALL + SWAP + LOADCP _MULFLOAT32 + CALL + LOADCP _DIVFLOAT32 + CALL + LOADCP _ADDFLOAT32 + CALL + STORE 32 ; CN + .LBRANCH _WHILE_START6_STDLIB + .CPOOL +_WHILE_END6_STDLIB: + LOAD 32 ; CN + LOADCP 1073741952 + LOADCP _MULFLOAT32 + CALL + LOAD 20 ; D + LOADCP _DIVFLOAT32 + CALL + STORE 16 ; C + .LBRANCH _IF_END28_STDLIB +_IF_ELSE28_STDLIB: + LOADCP MATHERROR ; MATHERROR + LOADCP RUNTIMEERROR + CALL +_IF_END28_STDLIB: + LOAD 8 ; A + LOAD 16 ; C + SWAP + LOADCP _INTTOFLOAT32 + CALL + SWAP + LOADCP _ADDFLOAT32 + CALL + STORE 4 ; LN + LOAD 4 ; LN + FPADJ 36 + RET +SQRT: + FPADJ -28 + STORE 0 ; N + LOAD 0 ; N + LOADC 0 + LOADCP _CMPFLOAT32 + CALL + LOADC 0 + CMP LT + .LCBRANCHZ _IF_ELSE29_STDLIB + LOADCP MATHERROR ; MATHERROR + LOADCP RUNTIMEERROR + CALL + .LBRANCH _IF_END29_STDLIB +_IF_ELSE29_STDLIB: + LOAD 0 ; N + LOADC 0 + LOADCP _CMPFLOAT32 + CALL + LOADC 0 + CMP EQ + .LCBRANCHZ _IF_ELSE30_STDLIB + LOADC 0 + STORE 4 ; SQRT + .LBRANCH _IF_END30_STDLIB +_IF_ELSE30_STDLIB: + LOAD 0 ; N + LOADCP 1073741952 + LOADCP _DIVFLOAT32 + CALL + STORE 12 ; GUESS + LOAD 0 ; N + LOADCP 100000 + LOADCP _INTTOFLOAT32 + CALL + LOADCP _DIVFLOAT32 + CALL + STORE 8 ; ERROR + LOADC 0 + STORE 20 ; DIFF +_REPEAT_START1_STDLIB: + LOAD 20 ; DIFF + STORE 24 ; LASTDIFF + LOAD 12 ; GUESS + LOAD 0 ; N + LOAD 12 ; GUESS + LOADCP _DIVFLOAT32 + CALL + LOADCP _ADDFLOAT32 + CALL + LOADC -1 + LOADCP SHIFTFLOAT32 + CALL + STORE 16 ; NEWGUESS + LOAD 16 ; NEWGUESS + LOAD 12 ; GUESS + LOADCP _SUBFLOAT32 + CALL + LOADCP $7FFFFFFF + AND + STORE 20 ; DIFF + LOAD 16 ; NEWGUESS + STORE 12 ; GUESS + LOAD 20 ; DIFF + LOAD 8 ; ERROR + LOADCP _CMPFLOAT32 + CALL + LOADC 0 + CMP LT + LOAD 12 ; GUESS + LOADC 0 + LOADCP _CMPFLOAT32 + CALL + LOADC 0 + CMP EQ + OR + LOAD 20 ; DIFF + LOAD 24 ; LASTDIFF + LOADCP _CMPFLOAT32 + CALL + LOADC 0 + CMP EQ + OR + .LCBRANCHZ _REPEAT_START1_STDLIB +_REPEAT_END1_STDLIB: + LOAD 12 ; GUESS + STORE 4 ; SQRT +_IF_END30_STDLIB: +_IF_END29_STDLIB: + LOAD 4 ; SQRT + FPADJ 28 + RET +FLOOR: + FPADJ -8 + STORE 0 ; X + LOAD 0 ; X + LOADC 0 + LOADCP _CMPFLOAT32 + CALL + LOADC 0 + CMP LT + .LCBRANCHZ _IF_ELSE31_STDLIB + LOAD 0 ; X + LOADCP 2147483518 + LOADCP _SUBFLOAT32 + CALL + STORE 0 ; X +_IF_ELSE31_STDLIB: +_IF_END31_STDLIB: + LOAD 0 ; X + LOADCP _TRUNCFLOAT32 + CALL + STORE 4 ; FLOOR + LOAD 4 ; FLOOR + FPADJ 8 + RET +ROUND: + FPADJ -8 + STORE 0 ; X + LOAD 0 ; X + LOADCP 1073741950 + LOADCP _ADDFLOAT32 + CALL + LOADCP _TRUNCFLOAT32 + CALL + STORE 4 ; ROUND + LOAD 4 ; ROUND + FPADJ 8 + RET +_NST_STDLIB56SIN_TAYLOR: + FPADJ -28 + LOADREG BP + STORE 4 + DUP + STOREREG BP + STORE 0 + STORE 8 ; X + LOAD 8 ; X + LOAD 8 ; X + LOADCP _MULFLOAT32 + CALL + STORE 16 ; X2 + LOAD 16 ; X2 + LOAD 8 ; X + LOADCP _MULFLOAT32 + CALL + STORE 20 ; X3 + LOAD 20 ; X3 + LOAD 16 ; X2 + LOADCP _MULFLOAT32 + CALL + STORE 24 ; X5 + LOAD 8 ; X + LOAD 20 ; X3 + LOADCP 1610612865 + LOADCP _DIVFLOAT32 + CALL + LOADCP _SUBFLOAT32 + CALL + LOAD 24 ; X5 + LOADCP 2013266053 + LOADCP _DIVFLOAT32 + CALL + LOADCP _ADDFLOAT32 + CALL + STORE 12 ; SIN_TAYLOR + LOAD 12 ; SIN_TAYLOR + LOAD 4 + STOREREG BP + FPADJ 28 + RET +SIN: + FPADJ -24 + STORE 0 ; X + LOAD 0 ; X + LOADC 0 + LOADCP _INTTOFLOAT32 + CALL + LOADCP _CMPFLOAT32 + CALL + LOADC 0 + CMP LT + .LCBRANCHZ _IF_ELSE32_STDLIB + LOAD 0 ; X + LOADCP _NEGFLOAT32 + CALL + STORE 0 ; X + LOADC 1 + STORE 20 ; INVERT + .LBRANCH _IF_END32_STDLIB + .CPOOL +_IF_ELSE32_STDLIB: + LOADC 0 + STORE 20 ; INVERT +_IF_END32_STDLIB: + LOAD 0 ; X + LOADCP 1367130494 + LOADCP _MULFLOAT32 + CALL + LOADCP FLOOR + CALL + LOADCP _INTTOFLOAT32 + CALL + STORE 8 ; K + LOAD 0 ; X + LOAD 8 ; K + LOADCP 1686629759 + LOADCP _MULFLOAT32 + CALL + LOADCP _SUBFLOAT32 + CALL + STORE 12 ; Y + LOAD 8 ; K + LOADCP _TRUNCFLOAT32 + CALL + LOADC 4 + LOADCP _MOD + CALL + STORE 16 ; QUADRANT + LOAD 16 ; QUADRANT +_CASE_0_0_0_STDLIB: + DUP + LOADC 0 + CMP NE + .LCBRANCH _CASE_0_0_1_STDLIB +_CASE_0_0M_STDLIB: + LOAD 12 ; Y + LOADREG FP + LOADCP _NST_STDLIB56SIN_TAYLOR + CALL + STORE 4 ; SIN + .LBRANCH _CASE_0_STDLIB_END +_CASE_0_0_1_STDLIB: +_CASE_0_1_0_STDLIB: + DUP + LOADC 1 + CMP NE + .LCBRANCH _CASE_0_1_1_STDLIB +_CASE_0_1M_STDLIB: + LOADCP 1686629759 + LOAD 12 ; Y + LOADCP _SUBFLOAT32 + CALL + LOADREG FP + LOADCP _NST_STDLIB56SIN_TAYLOR + CALL + STORE 4 ; SIN + .LBRANCH _CASE_0_STDLIB_END +_CASE_0_1_1_STDLIB: +_CASE_0_2_0_STDLIB: + DUP + LOADC 2 + CMP NE + .LCBRANCH _CASE_0_2_1_STDLIB +_CASE_0_2M_STDLIB: + LOAD 12 ; Y + LOADREG FP + LOADCP _NST_STDLIB56SIN_TAYLOR + CALL + LOADCP _NEGFLOAT32 + CALL + STORE 4 ; SIN + .LBRANCH _CASE_0_STDLIB_END +_CASE_0_2_1_STDLIB: +_CASE_0_3_0_STDLIB: + DUP + LOADC 3 + CMP NE + .LCBRANCH _CASE_0_3_1_STDLIB +_CASE_0_3M_STDLIB: + LOADCP 1686629759 + LOAD 12 ; Y + LOADCP _SUBFLOAT32 + CALL + LOADREG FP + LOADCP _NST_STDLIB56SIN_TAYLOR + CALL + LOADCP _NEGFLOAT32 + CALL + STORE 4 ; SIN + .LBRANCH _CASE_0_STDLIB_END +_CASE_0_3_1_STDLIB: +_CASE_0_4_STDLIB: +_CASE_0_STDLIB_END: + DROP + LOAD 20 ; INVERT + .LCBRANCHZ _IF_ELSE33_STDLIB + LOAD 4 ; SIN + LOADCP _NEGFLOAT32 + CALL + STORE 4 ; SIN +_IF_ELSE33_STDLIB: +_IF_END33_STDLIB: + LOAD 4 ; SIN + FPADJ 24 + RET +COS: + FPADJ -8 + STORE 0 ; X + LOAD 0 ; X + LOADCP 1686629759 + LOADCP _ADDFLOAT32 + CALL + LOADCP SIN + CALL + STORE 4 ; COS + LOAD 4 ; COS + FPADJ 8 + RET +ARCTAN: + FPADJ -20 + STORE 0 ; X + LOAD 0 ; X + LOADC 0 + LOADCP _CMPFLOAT32 + CALL + LOADC 0 + CMP LT + .LCBRANCHZ _IF_ELSE34_STDLIB + LOAD 0 ; X + LOADCP _NEGFLOAT32 + CALL + STORE 0 ; X + LOADC 1 + STORE 16 ; NEGATE + .LBRANCH _IF_END34_STDLIB +_IF_ELSE34_STDLIB: + LOADC 0 + STORE 16 ; NEGATE +_IF_END34_STDLIB: + LOAD 0 ; X + LOADCP 1149555328 + LOADCP _CMPFLOAT32 + CALL + LOADC 0 + CMP GT + .LCBRANCHZ _IF_ELSE35_STDLIB + LOADCP 1686629759 + STORE 8 ; Y + LOADCP 1073741951 + LOAD 0 ; X + LOADCP _DIVFLOAT32 + CALL + LOADCP _NEGFLOAT32 + CALL + STORE 0 ; X + .LBRANCH _IF_END35_STDLIB +_IF_ELSE35_STDLIB: + LOAD 0 ; X + LOADCP 1779033725 + LOADCP _CMPFLOAT32 + CALL + LOADC 0 + CMP GT + .LCBRANCHZ _IF_ELSE36_STDLIB + LOADCP 1686629758 + STORE 8 ; Y + LOAD 0 ; X + LOADCP 1073741951 + LOADCP _SUBFLOAT32 + CALL + LOAD 0 ; X + LOADCP 1073741951 + LOADCP _ADDFLOAT32 + CALL + LOADCP _DIVFLOAT32 + CALL + STORE 0 ; X + .LBRANCH _IF_END36_STDLIB +_IF_ELSE36_STDLIB: + LOADC 0 + STORE 8 ; Y +_IF_END36_STDLIB: +_IF_END35_STDLIB: + LOAD 0 ; X + LOAD 0 ; X + LOADCP _MULFLOAT32 + CALL + STORE 12 ; Z + LOAD 8 ; Y + LOADCP 1383622779 + LOAD 12 ; Z + LOADCP _MULFLOAT32 + CALL + LOADCP 1192084092 + LOADCP _SUBFLOAT32 + CALL + LOAD 12 ; Z + LOADCP _MULFLOAT32 + CALL + LOADCP 1716072316 + LOADCP _ADDFLOAT32 + CALL + LOAD 12 ; Z + LOADCP _MULFLOAT32 + CALL + LOADCP 1431639165 + LOADCP _SUBFLOAT32 + CALL + LOAD 12 ; Z + LOADCP _MULFLOAT32 + CALL + LOAD 0 ; X + LOADCP _MULFLOAT32 + CALL + LOADCP _ADDFLOAT32 + CALL + LOAD 0 ; X + LOADCP _ADDFLOAT32 + CALL + STORE 8 ; Y + LOAD 16 ; NEGATE + .LCBRANCHZ _IF_ELSE37_STDLIB + LOAD 8 ; Y + LOADCP _NEGFLOAT32 + CALL + STORE 8 ; Y +_IF_ELSE37_STDLIB: +_IF_END37_STDLIB: + LOAD 8 ; Y + STORE 4 ; ARCTAN + LOAD 4 ; ARCTAN + FPADJ 20 + RET + .CPOOL +TANCOT: + FPADJ -32 + STORE 4 ; DOCOT + STORE 0 ; X + LOAD 0 ; X + LOADC 0 + LOADCP _INTTOFLOAT32 + CALL + LOADCP _CMPFLOAT32 + CALL + LOADC 0 + CMP LT + .LCBRANCHZ _IF_ELSE38_STDLIB + LOAD 0 ; X + LOADCP _NEGFLOAT32 + CALL + STORE 0 ; X + LOADC 1 + STORE 28 ; NEGATE + .LBRANCH _IF_END38_STDLIB +_IF_ELSE38_STDLIB: + LOADC 0 + STORE 28 ; NEGATE +_IF_END38_STDLIB: + LOAD 0 ; X + LOADCP 1073741964 + LOADCP _CMPFLOAT32 + CALL + LOADC 0 + CMP GT + .LCBRANCHZ _IF_ELSE39_STDLIB + LOADCP MATHERROR ; MATHERROR + LOADCP RUNTIMEERROR + CALL +_IF_ELSE39_STDLIB: +_IF_END39_STDLIB: + LOADCP 1367130495 + LOAD 0 ; X + LOADCP _MULFLOAT32 + CALL + LOADCP _TRUNCFLOAT32 + CALL + STORE 24 ; J + LOAD 24 ; J + LOADCP _INTTOFLOAT32 + CALL + STORE 12 ; Y + LOAD 24 ; J + LOADC 1 + AND + LOADC 0 + CMP NE + .LCBRANCHZ _IF_ELSE40_STDLIB + LOAD 24 ; J + LOADC 1 + ADD + STORE 24 ; J + LOAD 12 ; Y + LOADCP 1073741951 + LOADCP _ADDFLOAT32 + CALL + STORE 12 ; Y +_IF_ELSE40_STDLIB: +_IF_END40_STDLIB: + LOAD 0 ; X + LOAD 12 ; Y + LOADCP 1686110334 + LOADCP _MULFLOAT32 + CALL + LOADCP _SUBFLOAT32 + CALL + LOAD 12 ; Y + LOADCP 2127560562 + LOADCP _MULFLOAT32 + CALL + LOADCP _SUBFLOAT32 + CALL + LOAD 12 ; Y + LOADCP 1360049254 + LOADCP _MULFLOAT32 + CALL + LOADCP _SUBFLOAT32 + CALL + STORE 16 ; Z + LOAD 16 ; Z + LOAD 16 ; Z + LOADCP _MULFLOAT32 + CALL + STORE 20 ; ZZ + LOAD 0 ; X + LOADCP 1759218545 + LOADCP _CMPFLOAT32 + CALL + LOADC 0 + CMP GT + .LCBRANCHZ _IF_ELSE41_STDLIB + LOADCP 1289919864 + LOAD 20 ; ZZ + LOADCP _MULFLOAT32 + CALL + LOADCP 1715195510 + LOADCP _ADDFLOAT32 + CALL + LOAD 20 ; ZZ + LOADCP _MULFLOAT32 + CALL + LOADCP 1678826105 + LOADCP _ADDFLOAT32 + CALL + LOAD 20 ; ZZ + LOADCP _MULFLOAT32 + CALL + LOADCP 1835197562 + LOADCP _ADDFLOAT32 + CALL + LOAD 20 ; ZZ + LOADCP _MULFLOAT32 + CALL + LOADCP 1145794172 + LOADCP _ADDFLOAT32 + CALL + LOAD 20 ; ZZ + LOADCP _MULFLOAT32 + CALL + LOADCP 1431648125 + LOADCP _ADDFLOAT32 + CALL + LOAD 20 ; ZZ + LOADCP _MULFLOAT32 + CALL + LOAD 16 ; Z + LOADCP _MULFLOAT32 + CALL + LOAD 16 ; Z + LOADCP _ADDFLOAT32 + CALL + STORE 12 ; Y + .LBRANCH _IF_END41_STDLIB +_IF_ELSE41_STDLIB: + LOAD 16 ; Z + STORE 12 ; Y +_IF_END41_STDLIB: + LOAD 24 ; J + LOADC 2 + AND + LOADC 0 + CMP NE + .LCBRANCHZ _IF_ELSE42_STDLIB + LOAD 4 ; DOCOT + .LCBRANCHZ _IF_ELSE43_STDLIB + LOAD 12 ; Y + LOADCP _NEGFLOAT32 + CALL + STORE 12 ; Y + .LBRANCH _IF_END43_STDLIB +_IF_ELSE43_STDLIB: + LOADCP -1073741697 + LOAD 12 ; Y + LOADCP _DIVFLOAT32 + CALL + STORE 12 ; Y +_IF_END43_STDLIB: + .LBRANCH _IF_END42_STDLIB +_IF_ELSE42_STDLIB: + LOAD 4 ; DOCOT + .LCBRANCHZ _IF_ELSE44_STDLIB + LOADCP 1073741951 + LOAD 12 ; Y + LOADCP _DIVFLOAT32 + CALL + STORE 12 ; Y +_IF_ELSE44_STDLIB: +_IF_END44_STDLIB: +_IF_END42_STDLIB: + LOAD 28 ; NEGATE + .LCBRANCHZ _IF_ELSE45_STDLIB + LOAD 12 ; Y + LOADCP _NEGFLOAT32 + CALL + STORE 12 ; Y +_IF_ELSE45_STDLIB: +_IF_END45_STDLIB: + LOAD 12 ; Y + STORE 8 ; TANCOT + LOAD 8 ; TANCOT + FPADJ 32 + RET +TAN: + FPADJ -8 + STORE 0 ; X + LOAD 0 ; X + LOADC 0 + LOADCP TANCOT + CALL + STORE 4 ; TAN + LOAD 4 ; TAN + FPADJ 8 + RET +COTAN: + FPADJ -8 + STORE 0 ; X + LOAD 0 ; X + LOADC 1 + LOADCP TANCOT + CALL + STORE 4 ; COTAN + LOAD 4 ; COTAN + FPADJ 8 + RET + .CPOOL +FILLCHAR: + FPADJ -28 + STORE 12 ; THECHAR + STORE 8 ; COUNT + STORE 4 ; STARTPOS + STORE 0 ; S + LOAD 0 ; S + LOADCP LENGTH + CALL + STORE 20 ; ENDPOS + LOAD 0 ; S + LOAD 20 ; ENDPOS + LOAD 8 ; COUNT + ADD + LOADCP _SETSTRINGLENGTH + CALL + LOAD 4 ; STARTPOS + LOAD 8 ; COUNT + ADD + STORE 24 ; P1 + LOAD 20 ; ENDPOS + STORE 16 ; I + LOAD 4 ; STARTPOS +_FOR_START4_STDLIB: + LOAD 16 ; I + OVER + CMP LT + .LCBRANCH _FOR_END4_STDLIB + LOAD 0 ; S + LOAD 16 ; I + LOAD 8 ; COUNT + ADD + LOADCP _INDEXSTRING + CALL + LOAD 0 ; S + LOAD 16 ; I + LOADCP _INDEXSTRING + CALL + LOADI.S1.X2Y + BSEL + LOADCP _SETSTRINGCHAR + CALL + LOAD 16 ; I + DEC 1 + STORE 16 ; I + .LBRANCH _FOR_START4_STDLIB +_FOR_END4_STDLIB: + DROP + LOAD 24 ; P1 + LOADC 1 + SUB + STORE 24 ; P1 + LOAD 4 ; STARTPOS + STORE 16 ; I + LOAD 24 ; P1 +_FOR_START5_STDLIB: + LOAD 16 ; I + OVER + CMP GT + .LCBRANCH _FOR_END5_STDLIB + LOAD 0 ; S + LOAD 16 ; I + LOADCP _INDEXSTRING + CALL + LOAD 12 ; THECHAR + LOADCP _SETSTRINGCHAR + CALL + LOAD 16 ; I + INC 1 + STORE 16 ; I + .LBRANCH _FOR_START5_STDLIB +_FOR_END5_STDLIB: + DROP + FPADJ 28 + RET +INTSTR: + FPADJ -44 + STORE 8 ; RBUF + STORE 4 ; FIELDWIDTH + STORE 0 ; V + LOADC 12 + ; BUF + LOADREG FP + INC 12 + LOADCP _INITSTRINGF + CALL + ; BUF + LOADREG FP + INC 12 + LOADCP _C_S_3_STDLIB + LOADCP _COPYSTRING + CALL + LOADC 0 + STORE 40 ; ISNEGATIVE + LOAD 0 ; V + LOADCP -2147483648 + CMP EQ + .LCBRANCHZ _IF_ELSE46_STDLIB + ; BUF + LOADREG FP + INC 12 + LOADCP _C_S_4_STDLIB + LOADCP _COPYSTRING + CALL + LOADC 1 + STORE 40 ; ISNEGATIVE + .LBRANCH _IF_END46_STDLIB +_IF_ELSE46_STDLIB: + LOAD 0 ; V + LOADC 0 + CMP LT + .LCBRANCHZ _IF_ELSE47_STDLIB + LOADC 1 + STORE 40 ; ISNEGATIVE + LOAD 0 ; V + NOT + INC 1 + STORE 0 ; V +_IF_ELSE47_STDLIB: +_IF_END47_STDLIB: +_REPEAT_START2_STDLIB: + LOAD 0 ; V + LOADC 10 + LOADCP _MOD + CALL + STORE 32 ; DIGIT + LOAD 0 ; V + LOADC 10 + LOADCP _DIV + CALL + STORE 0 ; V + ; BUF + LOADREG FP + INC 12 + ; BUF + LOADREG FP + INC 12 + LOADREG FP + LOADC 92 + SUB + SWAP + LOADC 80 + FPADJ -92 + LOADCP _INITSTRINGFROM + CALL + FPADJ 92 + LOADREG FP + LOADC 92 + SUB + LOAD 32 ; DIGIT + LOADC 48 + ADD + LOADREG FP + LOADC 104 + SUB + SWAP + OVER + LOADCP _CHARTOSTRING + CALL + FPADJ -104 + LOADCP _APPENDSTRING + CALL + FPADJ 104 + LOADREG FP + LOADC 92 + SUB + FPADJ -104 + LOADCP _COPYSTRING + CALL + FPADJ 104 + LOAD 0 ; V + LOADC 0 + CMP EQ + .LCBRANCHZ _REPEAT_START2_STDLIB +_REPEAT_END2_STDLIB: +_IF_END46_STDLIB: + LOAD 8 ; RBUF + LOADCP _C_S_3_STDLIB + LOADCP _COPYSTRING + CALL + LOAD 40 ; ISNEGATIVE + .LCBRANCHZ _IF_ELSE48_STDLIB + LOAD 8 ; RBUF + LOAD 8 ; RBUF + LOADREG FP + LOADC 88 + SUB + SWAP + LOADC 80 + FPADJ -88 + LOADCP _INITSTRINGFROM + CALL + FPADJ 88 + LOADREG FP + LOADC 88 + SUB + LOADCP _C_S_2_STDLIB + FPADJ -88 + LOADCP _APPENDSTRING + CALL + FPADJ 88 + LOADREG FP + LOADC 88 + SUB + FPADJ -88 + LOADCP _COPYSTRING + CALL + FPADJ 88 +_IF_ELSE48_STDLIB: +_IF_END48_STDLIB: + LOAD 4 ; FIELDWIDTH + LOAD 8 ; RBUF + LOADCP LENGTH + CALL + CMP GT + .LCBRANCHZ _IF_ELSE49_STDLIB + LOAD 8 ; RBUF + LOADC 1 + LOAD 4 ; FIELDWIDTH + LOAD 8 ; RBUF + LOADCP LENGTH + CALL + SUB + LOADC 32 + LOADCP FILLCHAR + CALL +_IF_ELSE49_STDLIB: +_IF_END49_STDLIB: + ; BUF + LOADREG FP + INC 12 + LOADCP LENGTH + CALL + STORE 36 ; I + LOADC 1 +_FOR_START6_STDLIB: + LOAD 36 ; I + OVER + CMP LT + .LCBRANCH _FOR_END6_STDLIB + LOAD 8 ; RBUF + LOAD 8 ; RBUF + LOADREG FP + LOADC 88 + SUB + SWAP + LOADC 80 + FPADJ -88 + LOADCP _INITSTRINGFROM + CALL + FPADJ 88 + LOADREG FP + LOADC 88 + SUB + ; BUF + LOADREG FP + INC 12 + LOAD 36 ; I + LOADCP _INDEXSTRING + CALL + LOADI.S1.X2Y + BSEL + LOADREG FP + LOADC 100 + SUB + SWAP + OVER + LOADCP _CHARTOSTRING + CALL + FPADJ -100 + LOADCP _APPENDSTRING + CALL + FPADJ 100 + LOADREG FP + LOADC 88 + SUB + FPADJ -100 + LOADCP _COPYSTRING + CALL + FPADJ 100 + LOAD 36 ; I + DEC 1 + STORE 36 ; I + .LBRANCH _FOR_START6_STDLIB + .CPOOL +_FOR_END6_STDLIB: + DROP + FPADJ 44 + RET +REALSTR: + FPADJ -32 + STORE 12 ; S + STORE 8 ; D + STORE 4 ; W + STORE 0 ; X + LOAD 4 ; W + LOADC 0 + CMP LT + LOAD 8 ; D + LOADC 0 + CMP LT + OR + .LCBRANCHZ _IF_ELSE50_STDLIB + LOADC 0 + STORE 4 ; W + LOADC 0 + STORE 8 ; D +_IF_ELSE50_STDLIB: +_IF_END50_STDLIB: + LOAD 0 ; X + LOADC 0 + LOADCP _INTTOFLOAT32 + CALL + LOADCP _CMPFLOAT32 + CALL + LOADC 0 + CMP LT + .LCBRANCHZ _IF_ELSE51_STDLIB + LOAD 0 ; X + LOADCP _NEGFLOAT32 + CALL + STORE 0 ; X + LOAD 12 ; S + LOADCP _C_S_2_STDLIB + LOADCP _COPYSTRING + CALL + .LBRANCH _IF_END51_STDLIB +_IF_ELSE51_STDLIB: + LOAD 12 ; S + LOADCP _C_S_5_STDLIB + LOADCP _COPYSTRING + CALL +_IF_END51_STDLIB: + LOADC 0 + STORE 24 ; EXPX + LOAD 0 ; X + STORE 28 ; NORMX + LOAD 0 ; X + LOADCP 1073741951 + LOADCP _CMPFLOAT32 + CALL + LOADC 0 + CMP GE + .LCBRANCHZ _IF_ELSE52_STDLIB +_WHILE_START7_STDLIB: + LOAD 28 ; NORMX + LOADCP 1342177410 + LOADCP _CMPFLOAT32 + CALL + LOADC 0 + CMP GE + .LCBRANCHZ _WHILE_END7_STDLIB + LOAD 24 ; EXPX + LOADC 1 + ADD + STORE 24 ; EXPX + LOAD 0 ; X + LOAD 24 ; EXPX + LOADCP PWROFTEN + CALL + LOADCP _DIVFLOAT32 + CALL + STORE 28 ; NORMX + .LBRANCH _WHILE_START7_STDLIB +_WHILE_END7_STDLIB: + .LBRANCH _IF_END52_STDLIB +_IF_ELSE52_STDLIB: + LOAD 0 ; X + LOADC 0 + LOADCP _INTTOFLOAT32 + CALL + LOADCP _CMPFLOAT32 + CALL + LOADC 0 + CMP NE + .LCBRANCHZ _IF_ELSE53_STDLIB +_REPEAT_START3_STDLIB: + LOAD 24 ; EXPX + LOADC 1 + SUB + STORE 24 ; EXPX + LOAD 0 ; X + LOAD 24 ; EXPX + NOT + INC 1 + LOADCP PWROFTEN + CALL + LOADCP _MULFLOAT32 + CALL + STORE 28 ; NORMX + LOAD 28 ; NORMX + LOADC 1 + LOADCP _INTTOFLOAT32 + CALL + LOADCP _CMPFLOAT32 + CALL + LOADC 0 + CMP GE + .LCBRANCHZ _REPEAT_START3_STDLIB +_REPEAT_END3_STDLIB: +_IF_ELSE53_STDLIB: +_IF_END53_STDLIB: +_IF_END52_STDLIB: + LOAD 8 ; D + LOADC 0 + CMP EQ + LOAD 8 ; D + LOAD 24 ; EXPX + ADD + LOADC 1 + ADD + LOADC 7 + CMP GT + OR + .LCBRANCHZ _IF_ELSE54_STDLIB + LOAD 28 ; NORMX + LOADC 5 + LOADCP _INTTOFLOAT32 + CALL + LOADC 7 + LOADCP PWROFTEN + CALL + LOADCP _DIVFLOAT32 + CALL + LOADCP _ADDFLOAT32 + CALL + STORE 28 ; NORMX + .LBRANCH _IF_END54_STDLIB +_IF_ELSE54_STDLIB: + LOAD 8 ; D + LOAD 24 ; EXPX + ADD + LOADC 1 + ADD + LOADC 0 + LOADCP _CMPINTFLOAT32 + CALL + LOADC 0 + CMP GE + .LCBRANCHZ _IF_ELSE55_STDLIB + LOAD 28 ; NORMX + LOADC 5 + LOADCP _INTTOFLOAT32 + CALL + LOAD 8 ; D + LOAD 24 ; EXPX + ADD + LOADC 1 + ADD + LOADCP PWROFTEN + CALL + LOADCP _DIVFLOAT32 + CALL + LOADCP _ADDFLOAT32 + CALL + STORE 28 ; NORMX +_IF_ELSE55_STDLIB: +_IF_END55_STDLIB: +_IF_END54_STDLIB: + LOAD 28 ; NORMX + LOADCP 1342177410 + LOADCP _CMPFLOAT32 + CALL + LOADC 0 + CMP GE + .LCBRANCHZ _IF_ELSE56_STDLIB + LOAD 24 ; EXPX + LOADC 1 + ADD + STORE 24 ; EXPX + LOAD 28 ; NORMX + LOADCP 1342177410 + LOADCP _DIVFLOAT32 + CALL + STORE 28 ; NORMX +_IF_ELSE56_STDLIB: +_IF_END56_STDLIB: + LOADC 1 + STORE 16 ; J + LOADC 7 +_FOR_START7_STDLIB: + LOAD 16 ; J + OVER + CMP GT + .LCBRANCH _FOR_END7_STDLIB + LOAD 28 ; NORMX + LOADCP _TRUNCFLOAT32 + CALL + STORE 20 ; TRUNCX + LOAD 12 ; S + LOAD 12 ; S + LOADREG FP + LOADC 92 + SUB + SWAP + LOADC 80 + FPADJ -92 + LOADCP _INITSTRINGFROM + CALL + FPADJ 92 + LOADREG FP + LOADC 92 + SUB + LOAD 20 ; TRUNCX + LOADC 48 + ADD + LOADREG FP + LOADC 104 + SUB + SWAP + OVER + LOADCP _CHARTOSTRING + CALL + FPADJ -104 + LOADCP _APPENDSTRING + CALL + FPADJ 104 + LOADREG FP + LOADC 92 + SUB + FPADJ -104 + LOADCP _COPYSTRING + CALL + FPADJ 104 + LOAD 28 ; NORMX + LOAD 20 ; TRUNCX + LOADCP _INTTOFLOAT32 + CALL + LOADCP _SUBFLOAT32 + CALL + LOADC 1 + LOADCP PWROFTEN + CALL + LOADCP _MULFLOAT32 + CALL + STORE 28 ; NORMX + LOAD 16 ; J + INC 1 + STORE 16 ; J + .LBRANCH _FOR_START7_STDLIB + .CPOOL +_FOR_END7_STDLIB: + DROP + LOAD 8 ; D + LOADC 0 + CMP EQ + LOAD 24 ; EXPX + LOADC 6 + CMP GE + OR + .LCBRANCHZ _IF_ELSE57_STDLIB + LOADC 46 + LOADREG FP + DEC 12 + SWAP + OVER + LOADCP _CHARTOSTRING + CALL + LOAD 12 ; S + LOADC 3 + FPADJ -12 + LOADCP INSERT + CALL + FPADJ 12 + LOAD 24 ; EXPX + LOADC 0 + CMP NE + .LCBRANCHZ _IF_ELSE58_STDLIB + LOAD 12 ; S + LOAD 12 ; S + LOADREG FP + LOADC 92 + SUB + SWAP + LOADC 80 + FPADJ -92 + LOADCP _INITSTRINGFROM + CALL + FPADJ 92 + LOADREG FP + LOADC 92 + SUB + LOADCP _C_S_6_STDLIB + FPADJ -92 + LOADCP _APPENDSTRING + CALL + FPADJ 92 + LOADREG FP + LOADC 92 + SUB + FPADJ -92 + LOADCP _COPYSTRING + CALL + FPADJ 92 + LOAD 24 ; EXPX + LOADC 0 + CMP LT + .LCBRANCHZ _IF_ELSE59_STDLIB + LOAD 12 ; S + LOAD 12 ; S + LOADREG FP + LOADC 92 + SUB + SWAP + LOADC 80 + FPADJ -92 + LOADCP _INITSTRINGFROM + CALL + FPADJ 92 + LOADREG FP + LOADC 92 + SUB + LOADCP _C_S_2_STDLIB + FPADJ -92 + LOADCP _APPENDSTRING + CALL + FPADJ 92 + LOADREG FP + LOADC 92 + SUB + FPADJ -92 + LOADCP _COPYSTRING + CALL + FPADJ 92 + LOAD 24 ; EXPX + NOT + INC 1 + STORE 24 ; EXPX +_IF_ELSE59_STDLIB: +_IF_END59_STDLIB: + LOAD 24 ; EXPX + LOADC 9 + CMP GT + .LCBRANCHZ _IF_ELSE60_STDLIB + LOAD 12 ; S + LOAD 12 ; S + LOADREG FP + LOADC 92 + SUB + SWAP + LOADC 80 + FPADJ -92 + LOADCP _INITSTRINGFROM + CALL + FPADJ 92 + LOADREG FP + LOADC 92 + SUB + LOAD 24 ; EXPX + LOADC 10 + FPADJ -92 + LOADCP _DIV + CALL + FPADJ 92 + LOADC 48 + ADD + LOADREG FP + LOADC 104 + SUB + SWAP + OVER + LOADCP _CHARTOSTRING + CALL + FPADJ -104 + LOADCP _APPENDSTRING + CALL + FPADJ 104 + LOADREG FP + LOADC 92 + SUB + FPADJ -104 + LOADCP _COPYSTRING + CALL + FPADJ 104 +_IF_ELSE60_STDLIB: +_IF_END60_STDLIB: + LOAD 12 ; S + LOAD 12 ; S + LOADREG FP + LOADC 92 + SUB + SWAP + LOADC 80 + FPADJ -92 + LOADCP _INITSTRINGFROM + CALL + FPADJ 92 + LOADREG FP + LOADC 92 + SUB + LOAD 24 ; EXPX + LOADC 10 + FPADJ -92 + LOADCP _MOD + CALL + FPADJ 92 + LOADC 48 + ADD + LOADREG FP + LOADC 104 + SUB + SWAP + OVER + LOADCP _CHARTOSTRING + CALL + FPADJ -104 + LOADCP _APPENDSTRING + CALL + FPADJ 104 + LOADREG FP + LOADC 92 + SUB + FPADJ -104 + LOADCP _COPYSTRING + CALL + FPADJ 104 +_IF_ELSE58_STDLIB: +_IF_END58_STDLIB: + .LBRANCH _IF_END57_STDLIB +_IF_ELSE57_STDLIB: + LOAD 24 ; EXPX + LOADC 0 + CMP GE + .LCBRANCHZ _IF_ELSE61_STDLIB + LOADC 46 + LOADREG FP + DEC 12 + SWAP + OVER + LOADCP _CHARTOSTRING + CALL + LOAD 12 ; S + LOADC 3 + LOAD 24 ; EXPX + ADD + FPADJ -12 + LOADCP INSERT + CALL + FPADJ 12 + LOADC 1 + STORE 16 ; J + LOAD 8 ; D + LOADC 5 + LOAD 24 ; EXPX + SUB + SUB +_FOR_START8_STDLIB: + LOAD 16 ; J + OVER + CMP GT + .LCBRANCH _FOR_END8_STDLIB + LOAD 12 ; S + LOAD 12 ; S + LOADREG FP + LOADC 92 + SUB + SWAP + LOADC 80 + FPADJ -92 + LOADCP _INITSTRINGFROM + CALL + FPADJ 92 + LOADREG FP + LOADC 92 + SUB + LOADCP _C_S_5_STDLIB + FPADJ -92 + LOADCP _APPENDSTRING + CALL + FPADJ 92 + LOADREG FP + LOADC 92 + SUB + FPADJ -92 + LOADCP _COPYSTRING + CALL + FPADJ 92 + LOAD 16 ; J + INC 1 + STORE 16 ; J + .LBRANCH _FOR_START8_STDLIB + .CPOOL +_FOR_END8_STDLIB: + DROP + LOAD 12 ; S + LOADC 3 + LOAD 24 ; EXPX + ADD + LOAD 8 ; D + ADD + LOADCP _SETSTRINGLENGTH + CALL + .LBRANCH _IF_END61_STDLIB +_IF_ELSE61_STDLIB: + LOADCP _C_S_7_STDLIB + LOAD 12 ; S + LOADC 2 + LOADCP INSERT + CALL + LOADC 1 + STORE 16 ; J + LOAD 24 ; EXPX + NOT + INC 1 + LOADC 1 + SUB +_FOR_START9_STDLIB: + LOAD 16 ; J + OVER + CMP GT + .LCBRANCH _FOR_END9_STDLIB + LOADC 48 + LOADREG FP + DEC 12 + SWAP + OVER + LOADCP _CHARTOSTRING + CALL + LOAD 12 ; S + LOADC 4 + FPADJ -12 + LOADCP INSERT + CALL + FPADJ 12 + LOAD 16 ; J + INC 1 + STORE 16 ; J + .LBRANCH _FOR_START9_STDLIB +_FOR_END9_STDLIB: + DROP + LOAD 12 ; S + LOADC 3 + LOAD 8 ; D + ADD + LOADCP _SETSTRINGLENGTH + CALL +_IF_END61_STDLIB: +_IF_END57_STDLIB: + LOAD 4 ; W + LOAD 12 ; S + LOADCP LENGTH + CALL + CMP GT + .LCBRANCHZ _IF_ELSE62_STDLIB + LOAD 12 ; S + LOADC 1 + LOAD 4 ; W + LOAD 12 ; S + LOADCP LENGTH + CALL + SUB + LOADC 32 + LOADCP FILLCHAR + CALL +_IF_ELSE62_STDLIB: +_IF_END62_STDLIB: + FPADJ 32 + RET +ISDIGIT: + FPADJ -8 + STORE 0 ; ACHAR + LOAD 0 ; ACHAR + LOADC 48 + CMP GE + LOAD 0 ; ACHAR + LOADC 57 + CMP LE + AND + STORE 4 ; ISDIGIT + LOAD 4 ; ISDIGIT + FPADJ 8 + RET +ISWHITE: + FPADJ -8 + STORE 0 ; ACHAR + LOAD 0 ; ACHAR + LOADCP _C_A_5_STDLIB + LOADC 4 + LOADCP _ISINTINARRAY + CALL + STORE 4 ; ISWHITE + LOAD 4 ; ISWHITE + FPADJ 8 + RET +SKIPWHITE: + FPADJ -16 + STORE 4 ; I + STORE 0 ; S + LOAD 0 ; S + DUP + LOADI + SWAP + INC 8 +_FOR_START10_STDLIB: + OVER + .LCBRANCHZ _FOR_END10_STDLIB + DUP + LOADI.S1.X2Y + BSEL + STORE 12 ; C + LOAD 12 ; C + LOADCP _C_A_6_STDLIB + LOADC 4 + LOADCP _ISINTINARRAY + CALL + LOADC 0 + CMP EQ + .LCBRANCHZ _IF_ELSE63_STDLIB + .LBRANCH _FOR_END10_STDLIB + .LBRANCH _IF_END63_STDLIB +_IF_ELSE63_STDLIB: + LOAD 4 ; I + LOAD 4 ; I + LOADI + LOADC 1 + ADD + STOREI + DROP +_IF_END63_STDLIB: + INC 1 + SWAP + DEC 1 + SWAP + .LBRANCH _FOR_START10_STDLIB +_FOR_END10_STDLIB: + DROP + DROP + FPADJ 16 + RET +INTVAL: + FPADJ -124 + STORE 92 ; CODE + STORE 88 ; VALUE + ; S + LOADREG FP + SWAP + LOADC 80 + LOADCP _INITSTRINGFROM + CALL + LOADC 1 + STORE 96 ; I + LOADC 0 + STORE 100 ; V + ; S + LOADREG FP + LOADCP LENGTH + CALL + STORE 104 ; L + LOADC 0 + STORE 116 ; NEGATE + LOADC 0 + STORE 120 ; VALID + ; S + LOADREG FP + ; I + LOADREG FP + LOADC 96 + ADD + LOADCP SKIPWHITE + CALL + LOAD 92 ; CODE + LOAD 104 ; L + LOADC 1 + ADD + STOREI + DROP + ; S + LOADREG FP + LOADCP LENGTH + CALL + LOAD 96 ; I + CMP GE + .LCBRANCHZ _IF_ELSE64_STDLIB + ; S + LOADREG FP + LOAD 96 ; I + LOADCP _INDEXSTRING + CALL + LOADI.S1.X2Y + BSEL + STORE 112 ; DIGIT + LOAD 112 ; DIGIT + LOADC 45 + CMP EQ + .LCBRANCHZ _IF_ELSE65_STDLIB + LOADC 1 + STORE 116 ; NEGATE + LOAD 96 ; I + LOADC 1 + ADD + STORE 96 ; I + .LBRANCH _IF_END65_STDLIB + .CPOOL +_IF_ELSE65_STDLIB: + LOAD 112 ; DIGIT + LOADC 43 + CMP EQ + .LCBRANCHZ _IF_ELSE66_STDLIB + LOAD 96 ; I + LOADC 1 + ADD + STORE 96 ; I +_IF_ELSE66_STDLIB: +_IF_END66_STDLIB: +_IF_END65_STDLIB: +_WHILE_START8_STDLIB: + LOAD 96 ; I + LOAD 104 ; L + CMP LE + .LCBRANCHZ _WHILE_END8_STDLIB + ; S + LOADREG FP + LOAD 96 ; I + LOADCP _INDEXSTRING + CALL + LOADI.S1.X2Y + BSEL + STORE 112 ; DIGIT + LOAD 112 ; DIGIT + LOADCP ISDIGIT + CALL + STORE 120 ; VALID + LOAD 120 ; VALID + .LCBRANCHZ _IF_ELSE67_STDLIB + LOAD 112 ; DIGIT + LOADC 48 + SUB + STORE 108 ; D + LOAD 100 ; V + LOADC 10 + LOADCP _MUL + CALL + LOAD 108 ; D + ADD + STORE 100 ; V + .LBRANCH _IF_END67_STDLIB +_IF_ELSE67_STDLIB: + LOAD 92 ; CODE + LOAD 96 ; I + STOREI + DROP + .LBRANCH _WHILE_END8_STDLIB +_IF_END67_STDLIB: + LOAD 96 ; I + LOADC 1 + ADD + STORE 96 ; I + .LBRANCH _WHILE_START8_STDLIB +_WHILE_END8_STDLIB: +_IF_ELSE64_STDLIB: +_IF_END64_STDLIB: + LOAD 120 ; VALID + LOAD 96 ; I + LOAD 104 ; L + LOADC 1 + ADD + CMP EQ + AND + .LCBRANCHZ _IF_ELSE68_STDLIB + LOAD 116 ; NEGATE + .LCBRANCHZ _IF_ELSE69_STDLIB + LOAD 88 ; VALUE + LOAD 100 ; V + NOT + INC 1 + STOREI + DROP + .LBRANCH _IF_END69_STDLIB +_IF_ELSE69_STDLIB: + LOAD 88 ; VALUE + LOAD 100 ; V + STOREI + DROP +_IF_END69_STDLIB: + LOAD 92 ; CODE + LOADC 0 + STOREI + DROP +_IF_ELSE68_STDLIB: +_IF_END68_STDLIB: + FPADJ 124 + RET +_NST_STDLIB70NEXTCHAR: + FPADJ -12 + LOADREG BP + STORE 4 + DUP + STOREREG BP + STORE 0 + LOAD.B 116 ; I + ; S + LOADREG BP + LOADCP LENGTH + CALL + CMP LE + .LCBRANCHZ _IF_ELSE70_STDLIB + ; S + LOADREG BP + LOAD.B 116 ; I + LOADCP _INDEXSTRING + CALL + LOADI.S1.X2Y + BSEL + STORE 8 ; NEXTCHAR + LOAD.B 116 ; I + LOADC 1 + ADD + STORE.B 116 ; I + LOADC 0 + STORE.B 120 ; FEOF + .LBRANCH _IF_END70_STDLIB +_IF_ELSE70_STDLIB: + LOADC 0 + STORE 8 ; NEXTCHAR + LOADC 1 + STORE.B 120 ; FEOF +_IF_END70_STDLIB: + LOAD 8 ; NEXTCHAR + LOAD 4 + STOREREG BP + FPADJ 12 + RET +_NST_STDLIB71SREADINT: + FPADJ -28 + LOADREG BP + STORE 4 + DUP + STOREREG BP + STORE 0 + STORE 8 ; E + LOADC 4 + ; DIGITS + LOADREG FP + INC 12 + LOADCP _INITSTRINGF + CALL + LOAD 8 ; E + LOADC 0 + STOREI + DROP + ; DIGITS + LOADREG FP + INC 12 + ; S + LOADREG BP + LOAD.B 116 ; I + LOADC 4 + LOADC 80 + LOADREG FP + LOADC 88 + SUB + LOADCP _INITSTRINGF + CALL + LOADREG FP + LOADC 88 + SUB + FPADJ -88 + LOADCP COPY + CALL + FPADJ 88 + FPADJ -88 + LOADCP _COPYSTRING + CALL + FPADJ 88 + ; DIGITS + LOADREG FP + INC 12 + LOAD 8 ; E + ; STATUS + LOADREG FP + LOADC 24 + ADD + LOADCP INTVAL + CALL + LOAD 24 ; STATUS + LOADC 0 + CMP NE + .LCBRANCHZ _IF_ELSE71_STDLIB + LOAD.B 116 ; I + LOAD 24 ; STATUS + ADD + STORE.B 116 ; I + LOADC 0 + STORE.B 104 ; XVALID + .LBRANCH _IF_END71_STDLIB +_IF_ELSE71_STDLIB: + LOAD.B 116 ; I + ; DIGITS + LOADREG FP + INC 12 + LOADCP LENGTH + CALL + ADD + STORE.B 116 ; I +_IF_END71_STDLIB: + LOAD 4 + STOREREG BP + FPADJ 28 + RET +REALVAL: + FPADJ -128 + STORE 92 ; CODE + STORE 88 ; V + ; S + LOADREG FP + SWAP + LOADC 80 + LOADCP _INITSTRINGFROM + CALL + LOADC 1 + STORE 116 ; I + LOADC 0 + LOADCP _INTTOFLOAT32 + CALL + STORE 112 ; X + LOADC 0 + STORE 100 ; NEG + LOADC 0 + STORE 104 ; XVALID + ; S + LOADREG FP + ; I + LOADREG FP + LOADC 116 + ADD + LOADCP SKIPWHITE + CALL + LOADREG FP + LOADCP _NST_STDLIB70NEXTCHAR + CALL + STORE 96 ; CH + LOAD 96 ; CH + LOADC 43 + CMP EQ + LOAD 96 ; CH + LOADC 45 + CMP EQ + OR + .LCBRANCHZ _IF_ELSE72_STDLIB + LOAD 96 ; CH + LOADC 45 + CMP EQ + STORE 100 ; NEG + LOADREG FP + LOADCP _NST_STDLIB70NEXTCHAR + CALL + STORE 96 ; CH +_IF_ELSE72_STDLIB: +_IF_END72_STDLIB: +_WHILE_START9_STDLIB: + LOAD 96 ; CH + LOADCP ISDIGIT + CALL + LOAD 120 ; FEOF + LOADC 0 + CMP EQ + AND + .LCBRANCHZ _WHILE_END9_STDLIB + LOADC 1 + STORE 104 ; XVALID + LOAD 112 ; X + LOADC 10 + LOADCP _INTTOFLOAT32 + CALL + LOADCP _MULFLOAT32 + CALL + LOAD 96 ; CH + LOADC 48 + SUB + LOADCP _INTTOFLOAT32 + CALL + LOADCP _ADDFLOAT32 + CALL + STORE 112 ; X + LOADREG FP + LOADCP _NST_STDLIB70NEXTCHAR + CALL + STORE 96 ; CH + .LBRANCH _WHILE_START9_STDLIB + .CPOOL +_WHILE_END9_STDLIB: + LOAD 120 ; FEOF + .LCBRANCHZ _IF_ELSE73_STDLIB + .LBRANCH _L69EXT_STDLIB +_IF_ELSE73_STDLIB: +_IF_END73_STDLIB: + LOADC -1 + STORE 108 ; IPOT + LOAD 96 ; CH + LOADC 46 + CMP EQ + .LCBRANCHZ _IF_ELSE74_STDLIB + LOADC 0 + STORE 108 ; IPOT +_REPEAT_START4_STDLIB: + LOADREG FP + LOADCP _NST_STDLIB70NEXTCHAR + CALL + STORE 96 ; CH + LOAD 96 ; CH + LOADCP ISDIGIT + CALL + .LCBRANCHZ _IF_ELSE75_STDLIB + LOADC 1 + STORE 104 ; XVALID + LOAD 108 ; IPOT + LOADC 1 + ADD + STORE 108 ; IPOT + LOAD 96 ; CH + LOADC 48 + SUB + LOADCP _INTTOFLOAT32 + CALL + LOAD 108 ; IPOT + LOADCP PWROFTEN + CALL + LOADCP _DIVFLOAT32 + CALL + STORE 124 ; DIGITVAL + LOAD 112 ; X + LOAD 124 ; DIGITVAL + LOADCP _ADDFLOAT32 + CALL + STORE 112 ; X +_IF_ELSE75_STDLIB: +_IF_END75_STDLIB: + LOAD 120 ; FEOF + LOAD 96 ; CH + LOADCP ISDIGIT + CALL + LOADC 0 + CMP EQ + OR + .LCBRANCHZ _REPEAT_START4_STDLIB +_REPEAT_END4_STDLIB: + LOAD 120 ; FEOF + .LCBRANCHZ _IF_ELSE76_STDLIB + .LBRANCH _L69EXT_STDLIB +_IF_ELSE76_STDLIB: +_IF_END76_STDLIB: +_IF_ELSE74_STDLIB: +_IF_END74_STDLIB: + LOAD 96 ; CH + LOADC 101 + CMP EQ + LOAD 96 ; CH + LOADC 69 + CMP EQ + OR + LOAD 104 ; XVALID + LOAD 108 ; IPOT + LOADC 0 + CMP LT + OR + AND + .LCBRANCHZ _IF_ELSE77_STDLIB + ; IPOT + LOADREG FP + LOADC 108 + ADD + LOADREG FP + LOADCP _NST_STDLIB71SREADINT + CALL + LOAD 120 ; FEOF + .LCBRANCHZ _IF_ELSE78_STDLIB + .LBRANCH _L69EXT_STDLIB +_IF_ELSE78_STDLIB: +_IF_END78_STDLIB: + LOAD 108 ; IPOT + LOADC 0 + CMP LT + .LCBRANCHZ _IF_ELSE79_STDLIB + LOAD 112 ; X + LOAD 108 ; IPOT + LOADCP ABS + CALL + LOADCP PWROFTEN + CALL + LOADCP _DIVFLOAT32 + CALL + STORE 112 ; X + .LBRANCH _IF_END79_STDLIB +_IF_ELSE79_STDLIB: + LOAD 112 ; X + LOAD 108 ; IPOT + LOADCP PWROFTEN + CALL + LOADCP _MULFLOAT32 + CALL + STORE 112 ; X +_IF_END79_STDLIB: +_IF_ELSE77_STDLIB: +_IF_END77_STDLIB: +_L69EXT_STDLIB: + LOAD 116 ; I + ; S + LOADREG FP + LOADCP LENGTH + CALL + CMP LE + .LCBRANCHZ _IF_ELSE80_STDLIB + LOADC 0 + STORE 104 ; XVALID +_IF_ELSE80_STDLIB: +_IF_END80_STDLIB: + LOAD 104 ; XVALID + .LCBRANCHZ _IF_ELSE81_STDLIB + LOAD 100 ; NEG + .LCBRANCHZ _IF_ELSE82_STDLIB + LOAD 112 ; X + LOADCP _NEGFLOAT32 + CALL + STORE 112 ; X +_IF_ELSE82_STDLIB: +_IF_END82_STDLIB: + LOAD 88 ; V + LOAD 112 ; X + STOREI + DROP + LOAD 92 ; CODE + LOADC 0 + STOREI + DROP + .LBRANCH _IF_END81_STDLIB +_IF_ELSE81_STDLIB: + LOAD 92 ; CODE + LOAD 116 ; I + LOADC 1 + SUB + STOREI + DROP +_IF_END81_STDLIB: + FPADJ 128 + RET +CHECKERROR: + FPADJ -4 + STORE 0 ; FIL + LOAD 0 ; FIL + INC 4 + LOADI + LOADC 0 + CMP NE + .LCBRANCHZ _IF_ELSE83_STDLIB + LOAD 0 ; FIL + INC 8 + LOADI + LOADC 0 + CMP EQ + .LCBRANCHZ _IF_ELSE84_STDLIB + LOADCP IOERRORDESC ; IOERRORDESC + LOAD 0 ; FIL + INC 4 + LOADI + DUP + LOADC 12 + LOADCP _BOUNDSCHECK + CALL + LOADC 28 + LOADCP _MULU + CALL + ADD + LOADC 20 + OVER + LOADCP _INITSTRING + CALL + LOADCP RUNTIMEERROR + CALL + .LBRANCH _IF_END84_STDLIB + .CPOOL +_IF_ELSE84_STDLIB: + LOAD 0 ; FIL + INC 4 + LOADC 0 + STOREI + DROP + LOAD 0 ; FIL + INC 8 + LOADC 0 + STOREI + DROP +_IF_END84_STDLIB: +_IF_ELSE83_STDLIB: +_IF_END83_STDLIB: + FPADJ 4 + RET +HANDLEBACKSPACE: + FPADJ -24 + STORE 8 ; BYTESREMOVED + STORE 4 ; BUF + STORE 0 ; AFILE + LOAD 8 ; BYTESREMOVED + LOADC 0 + STOREI + DROP + LOAD 4 ; BUF + LOADCP LENGTH + CALL + STORE 12 ; LEN + LOAD 12 ; LEN + LOADC 0 + CMP GT + .LCBRANCHZ _IF_ELSE85_STDLIB + LOAD 0 ; AFILE + LOADC 16 + ADD + LOADI + LOADC 0 + CMP EQ + .LCBRANCHZ _IF_ELSE86_STDLIB + LOAD 0 ; AFILE + LOADC 8 + LOADCP WRITECHANNEL + CALL + LOAD 0 ; AFILE + LOADC 32 + LOADCP WRITECHANNEL + CALL + LOAD 0 ; AFILE + LOADC 8 + LOADCP WRITECHANNEL + CALL +_IF_ELSE86_STDLIB: +_IF_END86_STDLIB: +_REPEAT_START5_STDLIB: + LOAD 4 ; BUF + LOAD 12 ; LEN + LOADCP _INDEXSTRING + CALL + LOADI.S1.X2Y + BSEL + STORE 16 ; REMOVEDCHAR + LOAD 8 ; BYTESREMOVED + LOAD 8 ; BYTESREMOVED + LOADI + LOADC 1 + ADD + STOREI + DROP + LOAD 12 ; LEN + LOADC 1 + SUB + STORE 12 ; LEN + LOAD 16 ; REMOVEDCHAR + LOADC 192 + AND + STORE 20 ; HIGHBITS + LOAD 20 ; HIGHBITS + LOADC 128 + CMP NE + LOAD 12 ; LEN + LOADC 0 + CMP EQ + OR + .LCBRANCHZ _REPEAT_START5_STDLIB +_REPEAT_END5_STDLIB: + LOAD 4 ; BUF + LOAD 12 ; LEN + LOADCP _SETSTRINGLENGTH + CALL +_IF_ELSE85_STDLIB: +_IF_END85_STDLIB: + FPADJ 24 + RET +_NST_STDLIB75ISSEPARATOR: + FPADJ -16 + LOADREG BP + STORE 4 + DUP + STOREREG BP + STORE 0 + STORE 8 ; ACHAR + LOAD.B 4 ; MODE +_CASE_1_0_0_STDLIB: + DUP + LOADC 0 + CMP NE + .LCBRANCH _CASE_1_0_1_STDLIB +_CASE_1_0M_STDLIB: + LOAD 8 ; ACHAR + LOADCP ISDIGIT + CALL + LOAD 8 ; ACHAR + LOADC 45 + CMP EQ + OR + LOADC 0 + CMP EQ + STORE 12 ; ISSEPARATOR + .LBRANCH _CASE_1_STDLIB_END +_CASE_1_0_1_STDLIB: +_CASE_1_1_0_STDLIB: + DUP + LOADC 1 + CMP NE + .LCBRANCH _CASE_1_1_1_STDLIB +_CASE_1_1M_STDLIB: + LOAD 8 ; ACHAR + LOADCP ISDIGIT + CALL + LOAD 8 ; ACHAR + LOADCP _C_A_7_STDLIB + LOADC 5 + LOADCP _ISINTINARRAY + CALL + OR + LOADC 0 + CMP EQ + STORE 12 ; ISSEPARATOR + .LBRANCH _CASE_1_STDLIB_END +_CASE_1_1_1_STDLIB: +_CASE_1_2_0_STDLIB: + DUP + LOADC 2 + CMP NE + .LCBRANCH _CASE_1_2_1_STDLIB +_CASE_1_2M_STDLIB: + LOAD 8 ; ACHAR + LOADC 13 + CMP EQ + LOAD 8 ; ACHAR + LOADC 10 + CMP EQ + OR + STORE 12 ; ISSEPARATOR + .LBRANCH _CASE_1_STDLIB_END +_CASE_1_2_1_STDLIB: +_CASE_1_3_STDLIB: +_CASE_1_STDLIB_END: + DROP + LOAD 12 ; ISSEPARATOR + LOAD 4 + STOREREG BP + FPADJ 16 + RET +FSCANBUF: + FPADJ -40 + STORE 8 ; BUF + STORE 4 ; MODE + STORE 0 ; AFILE + LOAD 8 ; BUF + LOADCP MAXLENGTH + CALL + STORE 16 ; MAXBYTES + LOADC 0 + STORE 12 ; BYTESREAD + LOADC 0 + STORE 24 ; DONE + LOADC 0 + STORE 36 ; SKIPCHAR + LOAD 8 ; BUF + LOADCP _C_S_3_STDLIB + LOADCP _COPYSTRING + CALL + LOAD 0 ; AFILE + LOADC 16 + ADD + LOADI + LOADC 0 + CMP EQ + STORE 32 ; ISCHANNEL +_REPEAT_START6_STDLIB: + LOAD 0 ; AFILE + LOADCP EOF + CALL + .LCBRANCHZ _IF_ELSE87_STDLIB + LOADC 1 + STORE 24 ; DONE + .LBRANCH _IF_END87_STDLIB +_IF_ELSE87_STDLIB: + LOAD 0 ; AFILE + LOADCP FREADCHAR + CALL + STORE 20 ; ACHAR + LOAD 32 ; ISCHANNEL + .LCBRANCHZ _IF_ELSE88_STDLIB + LOAD 20 ; ACHAR + LOADC 127 + CMP EQ + .LCBRANCHZ _IF_ELSE89_STDLIB + LOAD 0 ; AFILE + LOADC 40 + ADD + LOADI + LOAD 0 ; AFILE + LOADC 36 + ADD + LOADI + OR + LOADC 0 + CMP EQ + .LCBRANCHZ _IF_ELSE90_STDLIB + LOAD 0 ; AFILE + LOAD 8 ; BUF + ; BYTESREMOVED + LOADREG FP + LOADC 28 + ADD + LOADCP HANDLEBACKSPACE + CALL + LOAD 12 ; BYTESREAD + LOAD 28 ; BYTESREMOVED + SUB + STORE 12 ; BYTESREAD +_IF_ELSE90_STDLIB: +_IF_END90_STDLIB: + LOADC 1 + STORE 36 ; SKIPCHAR + .LBRANCH _IF_END89_STDLIB + .CPOOL +_IF_ELSE89_STDLIB: + LOAD 20 ; ACHAR + LOADC 4 + CMP EQ + .LCBRANCHZ _IF_ELSE91_STDLIB + LOADC 1 + STORE 36 ; SKIPCHAR + .LBRANCH _IF_END91_STDLIB +_IF_ELSE91_STDLIB: + LOADC 0 + STORE 36 ; SKIPCHAR +_IF_END91_STDLIB: +_IF_END89_STDLIB: +_IF_ELSE88_STDLIB: +_IF_END88_STDLIB: + LOAD 36 ; SKIPCHAR + LOADC 0 + CMP EQ + .LCBRANCHZ _IF_ELSE92_STDLIB + LOAD 20 ; ACHAR + LOADREG FP + LOADCP _NST_STDLIB75ISSEPARATOR + CALL + .LCBRANCHZ _IF_ELSE93_STDLIB + LOADC 1 + STORE 24 ; DONE + LOAD 0 ; AFILE + LOAD 20 ; ACHAR + LOADCP PUSHBACK + CALL + .LBRANCH _IF_END93_STDLIB +_IF_ELSE93_STDLIB: + LOAD 8 ; BUF + LOAD 20 ; ACHAR + LOADCP APPENDCHAR + CALL + LOAD 12 ; BYTESREAD + LOADC 1 + ADD + STORE 12 ; BYTESREAD +_IF_END93_STDLIB: +_IF_ELSE92_STDLIB: +_IF_END92_STDLIB: +_IF_END87_STDLIB: + LOAD 12 ; BYTESREAD + LOAD 16 ; MAXBYTES + CMP EQ + .LCBRANCHZ _IF_ELSE94_STDLIB + LOADC 1 + STORE 24 ; DONE +_IF_ELSE94_STDLIB: +_IF_END94_STDLIB: + LOAD 24 ; DONE + .LCBRANCHZ _REPEAT_START6_STDLIB +_REPEAT_END6_STDLIB: + FPADJ 40 + RET +FSKIPWHITE: + FPADJ -8 + STORE 0 ; F +_REPEAT_START7_STDLIB: + LOAD 0 ; F + LOADCP FREADCHAR + CALL + STORE 4 ; C + LOAD 0 ; F + LOADCP EOF + CALL + LOAD 4 ; C + LOADCP ISWHITE + CALL + LOADC 0 + CMP EQ + OR + .LCBRANCHZ _REPEAT_START7_STDLIB +_REPEAT_END7_STDLIB: + LOAD 0 ; F + LOAD 4 ; C + LOADCP PUSHBACK + CALL + FPADJ 8 + RET +FREADINT: + FPADJ -44 + STORE 4 ; F + STORE 0 ; V + LOADC 24 + ; BUF + LOADREG FP + INC 8 + LOADCP _INITSTRINGF + CALL + LOADC -1 + STORE 40 ; ERRPOS + LOAD 4 ; F + LOADCP FSKIPWHITE + CALL + LOAD 4 ; F + LOADC 0 + ; BUF + LOADREG FP + INC 8 + LOADCP FSCANBUF + CALL + LOAD 4 ; F + INC 4 + LOADI + LOADC 0 + CMP EQ + .LCBRANCHZ _IF_ELSE95_STDLIB + ; BUF + LOADREG FP + INC 8 + LOAD 0 ; V + ; ERRPOS + LOADREG FP + LOADC 40 + ADD + LOADCP INTVAL + CALL +_IF_ELSE95_STDLIB: +_IF_END95_STDLIB: + LOAD 40 ; ERRPOS + LOADC 0 + CMP NE + .LCBRANCHZ _IF_ELSE96_STDLIB + LOAD 4 ; F + LOADC 10 + LOADCP FILEERROR + CALL + LOAD 4 ; F + LOADCP CHECKERROR + CALL +_IF_ELSE96_STDLIB: +_IF_END96_STDLIB: + FPADJ 44 + RET +FREADREAL: + FPADJ -60 + STORE 4 ; F + STORE 0 ; V + LOADC 40 + ; BUF + LOADREG FP + INC 8 + LOADCP _INITSTRINGF + CALL + LOAD 4 ; F + LOADCP FSKIPWHITE + CALL + LOAD 4 ; F + LOADC 1 + ; BUF + LOADREG FP + INC 8 + LOADCP FSCANBUF + CALL + LOAD 4 ; F + INC 4 + LOADI + LOADC 0 + CMP EQ + .LCBRANCHZ _IF_ELSE97_STDLIB + ; BUF + LOADREG FP + INC 8 + LOAD 0 ; V + ; ERRPOS + LOADREG FP + LOADC 56 + ADD + LOADCP REALVAL + CALL +_IF_ELSE97_STDLIB: +_IF_END97_STDLIB: + LOAD 56 ; ERRPOS + LOADC 0 + CMP NE + .LCBRANCHZ _IF_ELSE98_STDLIB + LOAD 4 ; F + LOADC 10 + LOADCP FILEERROR + CALL +_IF_ELSE98_STDLIB: +_IF_END98_STDLIB: + FPADJ 60 + RET +FREADSTRING: + FPADJ -8 + STORE 4 ; F + STORE 0 ; S + LOAD 4 ; F + LOADC 2 + LOAD 0 ; S + LOADCP FSCANBUF + CALL + FPADJ 8 + RET +SKIPEOLN: + FPADJ -8 + STORE 0 ; AFILE +_REPEAT_START8_STDLIB: + LOAD 0 ; AFILE + LOADCP FREADCHAR + CALL + STORE 4 ; ACHAR + LOAD 4 ; ACHAR + LOADC 13 + CMP EQ + LOAD 0 ; AFILE + LOADCP EOF + CALL + OR + .LCBRANCHZ _REPEAT_START8_STDLIB +_REPEAT_END8_STDLIB: + LOAD 0 ; AFILE + LOADC 16 + ADD + LOADI + LOADC 0 + CMP NE + .LCBRANCHZ _IF_ELSE99_STDLIB + LOAD 0 ; AFILE + LOADCP EOF + CALL + LOADC 0 + CMP EQ + .LCBRANCHZ _IF_ELSE100_STDLIB + LOAD 0 ; AFILE + LOADCP FREADCHAR + CALL + STORE 4 ; ACHAR + LOAD 4 ; ACHAR + LOADC 10 + CMP NE + .LCBRANCHZ _IF_ELSE101_STDLIB + LOAD 0 ; AFILE + LOAD 4 ; ACHAR + LOADCP PUSHBACK + CALL +_IF_ELSE101_STDLIB: +_IF_END101_STDLIB: +_IF_ELSE100_STDLIB: +_IF_END100_STDLIB: +_IF_ELSE99_STDLIB: +_IF_END99_STDLIB: + FPADJ 8 + RET + .CPOOL +SETDEFAULTVOLUME: + FPADJ -44 + ; VOLNAME + LOADREG FP + SWAP + LOADC 32 + LOADCP _INITSTRINGFROM + CALL + ; VOLNAME + LOADREG FP + LOADCP FINDVOLUME + CALL + STORE 40 ; VOLID + LOAD 40 ; VOLID + LOADC 0 + CMP GT + .LCBRANCHZ _IF_ELSE102_STDLIB + LOADCP DEFAULTVOLUME ; DEFAULTVOLUME + ; VOLNAME + LOADREG FP + LOADCP _COPYSTRING + CALL + LOADCP DEFAULTVOLUMEID ; DEFAULTVOLUMEID + LOAD 40 ; VOLID + STOREI + DROP +_IF_ELSE102_STDLIB: +_IF_END102_STDLIB: + FPADJ 44 + RET +ADDPARTITIONS: + FPADJ -20 + STORE 8 ; ISLAST + STORE 4 ; PARTBLK + STORE 0 ; DEVID + LOADC 0 + STORE 12 ; PARTNO + LOADC 0 + STORE 12 ; PARTNO + LOADC 7 +_FOR_START11_STDLIB: + LOAD 12 ; PARTNO + OVER + CMP GT + .LCBRANCH _FOR_END11_STDLIB + LOAD 4 ; PARTBLK + LOAD 12 ; PARTNO + DUP + LOADC 8 + LOADCP _BOUNDSCHECK + CALL + SHL 2 + SHL 2 + SHL 2 + ADD + LOADC 40 + ADD + LOADI + STORE 16 ; FLAGS + LOADC 2 + LOAD 16 ; FLAGS + LOADCP _TESTBIT + CALL + .LCBRANCHZ _IF_ELSE103_STDLIB + LOAD 8 ; ISLAST + LOADC 1 + STOREI + DROP +_IF_ELSE103_STDLIB: +_IF_END103_STDLIB: + LOADC 0 + LOAD 16 ; FLAGS + LOADCP _TESTBIT + CALL + .LCBRANCHZ _IF_ELSE104_STDLIB + LOADCP VOLUMECOUNT ; VOLUMECOUNT + LOADCP VOLUMECOUNT ; VOLUMECOUNT + LOADI + LOADC 1 + ADD + STOREI + DROP + LOADCP VOLUMETABLE ; VOLUMETABLE + LOADCP VOLUMECOUNT ; VOLUMECOUNT + LOADI + DEC 1 + DUP + LOADC 32 + LOADCP _BOUNDSCHECK + CALL + LOADC 96 + LOADCP _MULU + CALL + ADD + LOADREG FP + DEC 4 + SWAP + STOREI + DROP + LOADREG FP + DEC 4 + LOADI + LOAD 4 ; PARTBLK + LOAD 12 ; PARTNO + DUP + LOADC 8 + LOADCP _BOUNDSCHECK + CALL + SHL 2 + SHL 2 + SHL 2 + ADD + LOADC 16 + FPADJ -4 + LOADCP _COPYWORDS + CALL + FPADJ 4 + LOADREG FP + DEC 4 + LOADI + LOADC 64 + ADD + LOAD 0 ; DEVID + STOREI + DROP + LOADREG FP + DEC 4 + LOADI + LOADC 68 + ADD + LOAD 12 ; PARTNO + STOREI + DROP + LOADREG FP + DEC 4 + LOADI + LOADC 72 + ADD + LOADC 0 + STOREI + DROP + LOADREG FP + DEC 4 + LOADI + LOADC 76 + ADD + LOADC 0 + STOREI + DROP + LOADREG FP + DEC 4 + LOADI + LOADC 80 + ADD + LOADC 0 + STOREI + DROP + LOADREG FP + DEC 4 + LOADI + LOADC 84 + ADD + LOADC -1 + STOREI + DROP + LOADREG FP + DEC 4 + LOADI + LOADC 88 + ADD + LOADC 0 + STOREI + DROP + LOADREG FP + DEC 4 + LOADI + LOADC 92 + ADD + LOADC 0 + STOREI + DROP +_IF_ELSE104_STDLIB: +_IF_END104_STDLIB: + LOAD 12 ; PARTNO + INC 1 + STORE 12 ; PARTNO + .LBRANCH _FOR_START11_STDLIB +_FOR_END11_STDLIB: + DROP + FPADJ 20 + RET +READPARTITIONS: + LOADREG FP + LOADC 528 + SUB + STOREREG FP + STORE 0 ; DEVID + ; PARTBLK + LOADREG FP + INC 8 + LOADC 512 + LOADCP _CLEARMEM + CALL + LOADC 0 + STORE 4 ; BLKNO + LOADC 0 + STORE 520 ; ISLAST + LOADC 0 + STORE 524 ; ERROR + LOADC 0 + STORE 4 ; BLKNO + LOADC 7 +_FOR_START12_STDLIB: + LOAD 4 ; BLKNO + OVER + CMP GT + .LCBRANCH _FOR_END12_STDLIB + LOAD 4 ; BLKNO + ; PARTBLK + LOADREG FP + INC 8 + ; ERROR + LOADREG FP + LOADC 524 + ADD + LOAD 0 ; DEVID + LOADCP READPARTBLK + CALL + LOAD 524 ; ERROR + LOADC 0 + CMP EQ + .LCBRANCHZ _IF_ELSE105_STDLIB + LOAD 0 ; DEVID + ; PARTBLK + LOADREG FP + INC 8 + ; ISLAST + LOADREG FP + LOADC 520 + ADD + LOADCP ADDPARTITIONS + CALL + .LBRANCH _IF_END105_STDLIB + .CPOOL +_IF_ELSE105_STDLIB: + LOADCP _C_S_8_STDLIB + LOADCP OUTPUT + DUP + LOADCP CHECKERROR + CALL + SWAP + OVER + LOADC 0 + LOADCP FWRITESTRING + CALL + LOAD 4 ; BLKNO + OVER + LOADC 0 + LOADCP FWRITEINT + CALL + LOADCP NEWLINESTR + OVER + LOADC 0 + LOADCP FWRITESTRING + CALL + DROP +_IF_END105_STDLIB: + LOAD 520 ; ISLAST + LOAD 524 ; ERROR + LOADC 0 + CMP NE + OR + .LCBRANCHZ _IF_ELSE106_STDLIB + .LBRANCH _FOR_END12_STDLIB +_IF_ELSE106_STDLIB: +_IF_END106_STDLIB: + LOAD 4 ; BLKNO + INC 1 + STORE 4 ; BLKNO + .LBRANCH _FOR_START12_STDLIB +_FOR_END12_STDLIB: + DROP + LOADREG FP + LOADC 528 + ADD + STOREREG FP + RET +READDEVICE: + FPADJ -16 + STORE 12 ; ERROR + STORE 8 ; BUF + STORE 4 ; BLOCKNO + STORE 0 ; DEVICEID + LOAD 4 ; BLOCKNO + LOAD 8 ; BUF + LOAD 12 ; ERROR + LOAD 0 ; DEVICEID + LOADCP READBLOCK + CALL + FPADJ 16 + RET +WRITEDEVICE: + FPADJ -16 + STORE 12 ; ERROR + STORE 8 ; BUF + STORE 4 ; BLOCKNO + STORE 0 ; DEVICEID + LOAD 4 ; BLOCKNO + LOAD 8 ; BUF + LOAD 12 ; ERROR + LOAD 0 ; DEVICEID + LOADCP WRITEBLOCK + CALL + FPADJ 16 + RET +GETPHYSBLOCKNO: + FPADJ -12 + STORE 4 ; BLOCKNO + STORE 0 ; VOLUMEID + LOADCP VOLUMETABLE ; VOLUMETABLE + LOAD 0 ; VOLUMEID + DEC 1 + DUP + LOADC 32 + LOADCP _BOUNDSCHECK + CALL + LOADC 96 + LOADCP _MULU + CALL + ADD + LOADC 44 + ADD + LOADI + LOAD 4 ; BLOCKNO + ADD + STORE 8 ; GETPHYSBLOCKNO + LOAD 8 ; GETPHYSBLOCKNO + FPADJ 12 + RET +READVOLUMEBLKS: + FPADJ -32 + STORE 16 ; ERROR + STORE 12 ; BLKCOUNT + STORE 8 ; BLKNO + STORE 4 ; DESTBUF + STORE 0 ; VOLUMEID + LOAD 0 ; VOLUMEID + LOAD 8 ; BLKNO + LOADCP GETPHYSBLOCKNO + CALL + STORE 20 ; DEVICEBLK + LOADCP VOLUMETABLE ; VOLUMETABLE + LOAD 0 ; VOLUMEID + DEC 1 + DUP + LOADC 32 + LOADCP _BOUNDSCHECK + CALL + LOADC 96 + LOADCP _MULU + CALL + ADD + LOADC 64 + ADD + LOADI + STORE 24 ; DEVICEID + LOADC 0 + STORE 28 ; I +_WHILE_START10_STDLIB: + LOAD 12 ; BLKCOUNT + LOADC 0 + CMP GT + .LCBRANCHZ _WHILE_END10_STDLIB + LOAD 24 ; DEVICEID + LOAD 20 ; DEVICEBLK + ; DESTBUF + LOADREG FP + INC 4 + LOADI + LOAD 28 ; I + DUP + LOADC 8 + LOADCP _BOUNDSCHECK + CALL + BROT + LOADC -$100 + AND + SHL + ADD + LOAD 16 ; ERROR + LOADCP READDEVICE + CALL + LOAD 12 ; BLKCOUNT + LOADC 1 + SUB + STORE 12 ; BLKCOUNT + LOAD 20 ; DEVICEBLK + LOADC 1 + ADD + STORE 20 ; DEVICEBLK + LOAD 28 ; I + LOADC 1 + ADD + STORE 28 ; I + .LBRANCH _WHILE_START10_STDLIB +_WHILE_END10_STDLIB: + FPADJ 32 + RET +WRITEVOLUMEBLKS: + FPADJ -32 + STORE 16 ; ERROR + STORE 12 ; BLKCOUNT + STORE 8 ; BLKNO + STORE 4 ; SRCBUF + STORE 0 ; VOLUMEID + LOAD 0 ; VOLUMEID + LOAD 8 ; BLKNO + LOADCP GETPHYSBLOCKNO + CALL + STORE 20 ; DEVICEBLK + LOADCP VOLUMETABLE ; VOLUMETABLE + LOAD 0 ; VOLUMEID + DEC 1 + DUP + LOADC 32 + LOADCP _BOUNDSCHECK + CALL + LOADC 96 + LOADCP _MULU + CALL + ADD + LOADC 64 + ADD + LOADI + STORE 24 ; DEVICEID + LOADC 0 + STORE 28 ; I +_WHILE_START11_STDLIB: + LOAD 12 ; BLKCOUNT + LOADC 0 + CMP GT + .LCBRANCHZ _WHILE_END11_STDLIB + LOAD 24 ; DEVICEID + LOAD 20 ; DEVICEBLK + ; SRCBUF + LOADREG FP + INC 4 + LOADI + LOAD 28 ; I + DUP + LOADC 8 + LOADCP _BOUNDSCHECK + CALL + BROT + LOADC -$100 + AND + SHL + ADD + LOAD 16 ; ERROR + LOADCP WRITEDEVICE + CALL + LOAD 12 ; BLKCOUNT + LOADC 1 + SUB + STORE 12 ; BLKCOUNT + LOAD 20 ; DEVICEBLK + LOADC 1 + ADD + STORE 20 ; DEVICEBLK + LOAD 28 ; I + LOADC 1 + ADD + STORE 28 ; I + .LBRANCH _WHILE_START11_STDLIB + .CPOOL +_WHILE_END11_STDLIB: + FPADJ 32 + RET +FINDVOLUME: + FPADJ -96 + ; NAME + LOADREG FP + SWAP + LOADC 80 + LOADCP _INITSTRINGFROM + CALL + LOADCP INITDEVICES + CALL + LOADC 0 + STORE 88 ; FINDVOLUME + LOADC 1 + STORE 92 ; VOLIDX + LOADCP VOLUMECOUNT ; VOLUMECOUNT + LOADI +_FOR_START13_STDLIB: + LOAD 92 ; VOLIDX + OVER + CMP GT + .LCBRANCH _FOR_END13_STDLIB + LOADCP VOLUMETABLE ; VOLUMETABLE + LOAD 92 ; VOLIDX + DEC 1 + DUP + LOADC 32 + LOADCP _BOUNDSCHECK + CALL + LOADC 96 + LOADCP _MULU + CALL + ADD + ; NAME + LOADREG FP + LOADCP _CMPSTRING + CALL + .LCBRANCHZ _IF_ELSE107_STDLIB + LOAD 92 ; VOLIDX + STORE 88 ; FINDVOLUME + .LBRANCH _FOR_END13_STDLIB +_IF_ELSE107_STDLIB: +_IF_END107_STDLIB: + LOAD 92 ; VOLIDX + INC 1 + STORE 92 ; VOLIDX + .LBRANCH _FOR_START13_STDLIB +_FOR_END13_STDLIB: + DROP + LOAD 88 ; FINDVOLUME + FPADJ 96 + RET +FLUSHDIRCACHE: + FPADJ -8 + STORE 4 ; ERROR + STORE 0 ; VOLUMEID + LOADCP VOLUMETABLE ; VOLUMETABLE + LOAD 0 ; VOLUMEID + DEC 1 + DUP + LOADC 32 + LOADCP _BOUNDSCHECK + CALL + LOADC 96 + LOADCP _MULU + CALL + ADD + LOADREG FP + DEC 4 + SWAP + STOREI + DROP + LOADREG FP + DEC 4 + LOADI + LOADC 80 + ADD + LOADI + LOADC 0 + CMP NE + LOADREG FP + DEC 4 + LOADI + LOADC 84 + ADD + LOADI + LOADC 0 + CMP GE + AND + LOADREG FP + DEC 4 + LOADI + LOADC 88 + ADD + LOADI + AND + .LCBRANCHZ _IF_ELSE108_STDLIB + LOAD 0 ; VOLUMEID + LOADREG FP + DEC 4 + LOADI + LOADC 84 + ADD + LOADI + FPADJ -4 + LOADCP GETPHYSBLOCKNO + CALL + FPADJ 4 + LOADREG FP + DEC 4 + LOADI + LOADC 80 + ADD + LOADI + LOAD 4 ; ERROR + LOADREG FP + DEC 4 + LOADI + LOADC 64 + ADD + LOADI + FPADJ -4 + LOADCP WRITEDIRBLK + CALL + FPADJ 4 + LOADREG FP + DEC 4 + LOADI + LOADC 88 + ADD + LOADC 0 + STOREI + DROP +_IF_ELSE108_STDLIB: +_IF_END108_STDLIB: + FPADJ 8 + RET +OPENVOLUMEID: + FPADJ -4 + STORE 0 ; VOLID + LOADCP VOLUMETABLE ; VOLUMETABLE + LOAD 0 ; VOLID + DEC 1 + DUP + LOADC 32 + LOADCP _BOUNDSCHECK + CALL + LOADC 96 + LOADCP _MULU + CALL + ADD + LOADREG FP + DEC 4 + SWAP + STOREI + DROP + LOADREG FP + DEC 4 + LOADI + LOADC 80 + ADD + LOADI + LOADC 0 + CMP EQ + .LCBRANCHZ _IF_ELSE109_STDLIB + LOADREG FP + DEC 4 + LOADI + LOADC 80 + ADD + LOADC 512 + FPADJ -4 + LOADCP _MEM_ALLOC + CALL + FPADJ 4 + DUP + LOADC 512 + LOADCP _CLEARMEM + CALL + FPADJ -4 + LOADCP _CHECK_ALLOC + CALL + FPADJ 4 + STOREI + DROP +_IF_ELSE109_STDLIB: +_IF_END109_STDLIB: + LOADREG FP + DEC 4 + LOADI + LOADC 92 + ADD + LOADREG FP + DEC 4 + LOADI + LOADC 92 + ADD + LOADI + LOADC 1 + ADD + STOREI + DROP + FPADJ 4 + RET +CLOSEVOLUMEID: + FPADJ -8 + STORE 0 ; VOLID + LOADCP VOLUMETABLE ; VOLUMETABLE + LOAD 0 ; VOLID + DEC 1 + DUP + LOADC 32 + LOADCP _BOUNDSCHECK + CALL + LOADC 96 + LOADCP _MULU + CALL + ADD + LOADREG FP + DEC 4 + SWAP + STOREI + DROP + LOADREG FP + DEC 4 + LOADI + LOADC 92 + ADD + LOADREG FP + DEC 4 + LOADI + LOADC 92 + ADD + LOADI + LOADC 1 + SUB + STOREI + DROP + LOADREG FP + DEC 4 + LOADI + LOADC 92 + ADD + LOADI + LOADC 0 + CMP EQ + .LCBRANCHZ _IF_ELSE110_STDLIB + LOAD 0 ; VOLID + ; ERROR + LOADREG FP + INC 4 + FPADJ -4 + LOADCP FLUSHDIRCACHE + CALL + FPADJ 4 + LOADREG FP + DEC 4 + LOADI + LOADC 84 + ADD + LOADC -1 + STOREI + DROP + LOADREG FP + DEC 4 + LOADI + LOADC 80 + ADD + LOADI + FPADJ -4 + LOADCP _MEM_FREE + CALL + FPADJ 4 + LOADREG FP + DEC 4 + LOADI + LOADC 80 + ADD + LOADC 0 + STOREI + DROP +_IF_ELSE110_STDLIB: +_IF_END110_STDLIB: + FPADJ 8 + RET + .CPOOL +LOADDIRBLOCK: + FPADJ -12 + STORE 8 ; ERROR + STORE 4 ; DIRBLKNO + STORE 0 ; VOLUMEID + LOADCP VOLUMETABLE ; VOLUMETABLE + LOAD 0 ; VOLUMEID + DEC 1 + DUP + LOADC 32 + LOADCP _BOUNDSCHECK + CALL + LOADC 96 + LOADCP _MULU + CALL + ADD + LOADREG FP + DEC 4 + SWAP + STOREI + DROP + LOADREG FP + DEC 4 + LOADI + LOADC 84 + ADD + LOADI + LOAD 4 ; DIRBLKNO + CMP NE + .LCBRANCHZ _IF_ELSE111_STDLIB + LOAD 0 ; VOLUMEID + LOAD 8 ; ERROR + FPADJ -4 + LOADCP FLUSHDIRCACHE + CALL + FPADJ 4 + LOAD 0 ; VOLUMEID + LOAD 4 ; DIRBLKNO + FPADJ -4 + LOADCP GETPHYSBLOCKNO + CALL + FPADJ 4 + LOADREG FP + DEC 4 + LOADI + LOADC 80 + ADD + LOADI + LOAD 8 ; ERROR + LOADREG FP + DEC 4 + LOADI + LOADC 64 + ADD + LOADI + FPADJ -4 + LOADCP READDIRBLK + CALL + FPADJ 4 + LOADREG FP + DEC 4 + LOADI + LOADC 84 + ADD + LOAD 4 ; DIRBLKNO + STOREI + DROP +_IF_ELSE111_STDLIB: +_IF_END111_STDLIB: + FPADJ 12 + RET +GETDIRSLOT: + FPADJ -24 + STORE 12 ; ERROR + STORE 8 ; RESULT + STORE 4 ; SLOTNO + STORE 0 ; VOLUMEID + LOAD 12 ; ERROR + LOADC 0 + STOREI + DROP + LOADCP VOLUMETABLE ; VOLUMETABLE + LOAD 0 ; VOLUMEID + DEC 1 + DUP + LOADC 32 + LOADCP _BOUNDSCHECK + CALL + LOADC 96 + LOADCP _MULU + CALL + ADD + LOADREG FP + DEC 4 + SWAP + STOREI + DROP + LOAD 4 ; SLOTNO + LOADC 8 + FPADJ -4 + LOADCP _DIV + CALL + FPADJ 4 + STORE 16 ; DIRBLKNO + LOAD 4 ; SLOTNO + LOADC 8 + FPADJ -4 + LOADCP _MOD + CALL + FPADJ 4 + STORE 20 ; SLOTOFFSET + LOAD 0 ; VOLUMEID + LOAD 16 ; DIRBLKNO + LOAD 12 ; ERROR + FPADJ -4 + LOADCP LOADDIRBLOCK + CALL + FPADJ 4 + LOAD 8 ; RESULT + LOADREG FP + DEC 4 + LOADI + LOADC 80 + ADD + LOADI + LOAD 20 ; SLOTOFFSET + DUP + LOADC 8 + LOADCP _BOUNDSCHECK + CALL + SHL 2 + SHL 2 + SHL 2 + ADD + LOADC 16 + FPADJ -4 + LOADCP _COPYWORDS + CALL + FPADJ 4 + FPADJ 24 + RET +PUTDIRSLOT: + FPADJ -24 + STORE 12 ; ERROR + STORE 8 ; DIRSLOT + STORE 4 ; SLOTNO + STORE 0 ; VOLUMEID + LOADCP VOLUMETABLE ; VOLUMETABLE + LOAD 0 ; VOLUMEID + DEC 1 + DUP + LOADC 32 + LOADCP _BOUNDSCHECK + CALL + LOADC 96 + LOADCP _MULU + CALL + ADD + LOADREG FP + DEC 4 + SWAP + STOREI + DROP + LOAD 4 ; SLOTNO + LOADC 8 + FPADJ -4 + LOADCP _DIV + CALL + FPADJ 4 + STORE 16 ; DIRBLKNO + LOAD 4 ; SLOTNO + LOADC 8 + FPADJ -4 + LOADCP _MOD + CALL + FPADJ 4 + STORE 20 ; SLOTOFFSET + LOAD 0 ; VOLUMEID + LOAD 16 ; DIRBLKNO + LOAD 12 ; ERROR + FPADJ -4 + LOADCP LOADDIRBLOCK + CALL + FPADJ 4 + LOADREG FP + DEC 4 + LOADI + LOADC 80 + ADD + LOADI + LOAD 20 ; SLOTOFFSET + DUP + LOADC 8 + LOADCP _BOUNDSCHECK + CALL + SHL 2 + SHL 2 + SHL 2 + ADD + LOAD 8 ; DIRSLOT + LOADC 16 + FPADJ -4 + LOADCP _COPYWORDS + CALL + FPADJ 4 + LOADREG FP + DEC 4 + LOADI + LOADC 88 + ADD + LOADC 1 + STOREI + DROP + FPADJ 24 + RET +FINDDIRSLOT: + FPADJ -88 + STORE 4 ; ERROR + STORE 0 ; VOLID + ; DIRSLOT + LOADREG FP + LOADC 20 + ADD + LOADC 64 + LOADCP _CLEARMEM + CALL + LOADC -1 + STORE 8 ; FINDDIRSLOT + LOADCP VOLUMETABLE ; VOLUMETABLE + LOAD 0 ; VOLID + DEC 1 + DUP + LOADC 32 + LOADCP _BOUNDSCHECK + CALL + LOADC 96 + LOADCP _MULU + CALL + ADD + LOADREG FP + DEC 4 + SWAP + STOREI + DROP + LOADREG FP + DEC 4 + LOADI + LOADC 56 + ADD + LOADI + STORE 16 ; MAXSLOTS + LOADREG FP + DEC 4 + LOADI + LOADC 72 + ADD + LOADI + STORE 12 ; SLOTNO + LOADC 0 + STORE 84 ; DONE +_REPEAT_START9_STDLIB: + LOAD 0 ; VOLID + LOAD 12 ; SLOTNO + ; DIRSLOT + LOADREG FP + LOADC 20 + ADD + LOAD 4 ; ERROR + FPADJ -4 + LOADCP GETDIRSLOT + CALL + FPADJ 4 + LOADC 0 + LOAD 60 ; DIRSLOT + LOADCP _TESTBIT + CALL + .LCBRANCHZ _IF_ELSE112_STDLIB + LOAD 12 ; SLOTNO + STORE 8 ; FINDDIRSLOT + LOADC 1 + STORE 84 ; DONE + LOADREG FP + DEC 4 + LOADI + LOADC 76 + ADD + LOAD 12 ; SLOTNO + STOREI + DROP +_IF_ELSE112_STDLIB: +_IF_END112_STDLIB: + LOAD 12 ; SLOTNO + LOADC 1 + ADD + STORE 12 ; SLOTNO + LOAD 84 ; DONE + LOAD 12 ; SLOTNO + LOAD 16 ; MAXSLOTS + CMP GE + OR + LOAD 4 ; ERROR + LOADI + LOADC 0 + CMP NE + OR + .LCBRANCHZ _REPEAT_START9_STDLIB +_REPEAT_END9_STDLIB: + LOAD 8 ; FINDDIRSLOT + FPADJ 88 + RET + .CPOOL +READBUF: + FPADJ -12 + STORE 4 ; ERROR + STORE 0 ; FIL + LOAD 0 ; FIL + LOADC 32 + ADD + LOAD 0 ; FIL + LOADC 28 + ADD + LOADI + LOAD 0 ; FIL + LOADC 28 + ADD + LOADI + LOADC 512 + LOADCP _MOD + CALL + SUB + STOREI + DROP + LOAD 0 ; FIL + LOADC 32 + ADD + LOADI + LOADC 512 + LOADCP _DIV + CALL + LOAD 0 ; FIL + LOADC 24 + ADD + LOADI + LOAD 0 ; FIL + LOADC 48 + ADD + LOADI + LOADCP _MUL + CALL + ADD + STORE 8 ; BLKNO + LOAD 0 ; FIL + LOADC 20 + ADD + LOADI + LOAD 0 ; FIL + LOADC 56 + ADD + LOADI + LOAD 8 ; BLKNO + LOAD 0 ; FIL + LOADC 44 + ADD + LOADI + LOAD 4 ; ERROR + LOADCP READVOLUMEBLKS + CALL + FPADJ 12 + RET +FILEERROR: + FPADJ -8 + STORE 4 ; ERROR + STORE 0 ; FIL + LOAD 0 ; FIL + INC 4 + LOAD 4 ; ERROR + STOREI + DROP + LOAD 0 ; FIL + INC 8 + LOADC 0 + STOREI + DROP + FPADJ 8 + RET +IORESULT: + FPADJ -8 + STORE 0 ; FIL + LOAD 0 ; FIL + INC 4 + LOADI + STORE 4 ; IORESULT + LOAD 0 ; FIL + INC 8 + LOADC 1 + STOREI + DROP + LOAD 4 ; IORESULT + FPADJ 8 + RET +ERRORSTR: + FPADJ -8 + STORE 4 ; ERRORSTR + STORE 0 ; ERR + LOAD 0 ; ERR + LOADC 11 + CMP LE + .LCBRANCHZ _IF_ELSE113_STDLIB + LOAD 4 ; ERRORSTR + LOADCP IOERRORDESC ; IOERRORDESC + LOAD 0 ; ERR + DUP + LOADC 12 + LOADCP _BOUNDSCHECK + CALL + LOADC 28 + LOADCP _MULU + CALL + ADD + LOADCP _COPYSTRING + CALL + .LBRANCH _IF_END113_STDLIB +_IF_ELSE113_STDLIB: + LOAD 4 ; ERRORSTR + LOADCP _C_S_9_STDLIB + LOADCP _COPYSTRING + CALL +_IF_END113_STDLIB: + LOAD 4 ; ERRORSTR + FPADJ 8 + RET +EOF: + FPADJ -8 + STORE 0 ; FIL + LOAD 0 ; FIL + LOADC 16 + ADD + LOADI + LOADC 1 + CMP EQ + .LCBRANCHZ _IF_ELSE114_STDLIB + LOAD 0 ; FIL + LOADC 28 + ADD + LOADI + LOAD 0 ; FIL + LOADC 36 + ADD + LOADI + CMP GE + STORE 4 ; EOF + .LBRANCH _IF_END114_STDLIB +_IF_ELSE114_STDLIB: + LOAD 0 ; FIL + LOADC 32 + ADD + LOADI + STORE 4 ; EOF +_IF_END114_STDLIB: + LOAD 4 ; EOF + FPADJ 8 + RET +EOLN: + FPADJ -8 + STORE 0 ; FIL + LOAD 0 ; FIL + LOADCP EOF + CALL + LOAD 0 ; FIL + INC 12 + LOADI + OR + STORE 4 ; EOLN + LOAD 4 ; EOLN + FPADJ 8 + RET +READFS: + FPADJ -32 + STORE 8 ; LEN + STORE 4 ; DESTBUF + STORE 0 ; FIL + LOADC 0 + STORE 28 ; ERROR + LOADC 0 + STORE 20 ; DESTPOS + LOAD 0 ; FIL + LOADC 28 + ADD + LOADI + LOAD 8 ; LEN + ADD + LOAD 0 ; FIL + LOADC 36 + ADD + LOADI + CMP GT + .LCBRANCHZ _IF_ELSE115_STDLIB + LOAD 0 ; FIL + LOADC 36 + ADD + LOADI + LOAD 0 ; FIL + LOADC 28 + ADD + LOADI + SUB + STORE 8 ; LEN +_IF_ELSE115_STDLIB: +_IF_END115_STDLIB: +_WHILE_START12_STDLIB: + LOAD 8 ; LEN + LOADC 0 + CMP GT + LOAD 28 ; ERROR + LOADC 0 + CMP EQ + AND + .LCBRANCHZ _WHILE_END12_STDLIB + LOAD 0 ; FIL + LOADC 60 + ADD + LOADI + LOAD 0 ; FIL + LOADC 64 + ADD + LOADI + CMP LT + .LCBRANCHZ _IF_ELSE116_STDLIB + LOAD 0 ; FIL + LOADC 64 + ADD + LOADI + LOAD 0 ; FIL + LOADC 60 + ADD + LOADI + SUB + STORE 12 ; BUFLEFT + LOAD 8 ; LEN + LOAD 12 ; BUFLEFT + CMP GT + .LCBRANCHZ _IF_ELSE117_STDLIB + LOAD 12 ; BUFLEFT + STORE 16 ; PARTIAL + .LBRANCH _IF_END117_STDLIB + .CPOOL +_IF_ELSE117_STDLIB: + LOAD 8 ; LEN + STORE 16 ; PARTIAL +_IF_END117_STDLIB: + LOAD 4 ; DESTBUF + LOAD 20 ; DESTPOS + LOAD 0 ; FIL + LOADC 56 + ADD + LOADI + LOAD 0 ; FIL + LOADC 60 + ADD + LOADI + LOAD 16 ; PARTIAL + LOADCP COPYBUF + CALL + LOAD 8 ; LEN + LOAD 16 ; PARTIAL + SUB + STORE 8 ; LEN + LOAD 0 ; FIL + LOADC 60 + ADD + LOAD 0 ; FIL + LOADC 60 + ADD + LOADI + LOAD 16 ; PARTIAL + ADD + STOREI + DROP + LOAD 0 ; FIL + LOADC 28 + ADD + LOAD 0 ; FIL + LOADC 28 + ADD + LOADI + LOAD 16 ; PARTIAL + ADD + STOREI + DROP + LOAD 20 ; DESTPOS + LOAD 16 ; PARTIAL + ADD + STORE 20 ; DESTPOS + .LBRANCH _IF_END116_STDLIB +_IF_ELSE116_STDLIB: + LOAD 0 ; FIL + ; ERROR + LOADREG FP + LOADC 28 + ADD + LOADCP READBUF + CALL + LOAD 0 ; FIL + LOADC 60 + ADD + LOADC 0 + STOREI + DROP +_IF_END116_STDLIB: + .LBRANCH _WHILE_START12_STDLIB +_WHILE_END12_STDLIB: + LOAD 28 ; ERROR + LOADC 0 + CMP NE + .LCBRANCHZ _IF_ELSE118_STDLIB + LOAD 0 ; FIL + LOAD 28 ; ERROR + LOADCP FILEERROR + CALL +_IF_ELSE118_STDLIB: +_IF_END118_STDLIB: + FPADJ 32 + RET +FLUSHFILE: + FPADJ -12 + STORE 0 ; FIL + LOAD 0 ; FIL + LOADC 32 + ADD + LOADI + LOADC 512 + LOADCP _DIV + CALL + LOAD 0 ; FIL + LOADC 24 + ADD + LOADI + LOAD 0 ; FIL + LOADC 48 + ADD + LOADI + LOADCP _MUL + CALL + ADD + STORE 4 ; BLKNO + LOAD 0 ; FIL + LOADC 20 + ADD + LOADI + LOAD 0 ; FIL + LOADC 56 + ADD + LOADI + LOAD 4 ; BLKNO + LOAD 0 ; FIL + LOADC 44 + ADD + LOADI + ; ERROR + LOADREG FP + INC 8 + LOADCP WRITEVOLUMEBLKS + CALL + LOAD 8 ; ERROR + LOADC 0 + CMP NE + .LCBRANCHZ _IF_ELSE119_STDLIB + LOAD 0 ; FIL + LOAD 8 ; ERROR + LOADCP FILEERROR + CALL +_IF_ELSE119_STDLIB: +_IF_END119_STDLIB: + LOAD 0 ; FIL + LOADC 68 + ADD + LOADC 0 + STOREI + DROP + FPADJ 12 + RET +SEEK: + FPADJ -16 + STORE 4 ; POSITION + STORE 0 ; FIL + LOAD 0 ; FIL + LOADCP CHECKERROR + CALL + LOAD 0 ; FIL + LOADC 16 + ADD + LOADI + LOADC 0 + CMP EQ + .LCBRANCHZ _IF_ELSE120_STDLIB + LOAD 0 ; FIL + LOADC 6 + LOADCP FILEERROR + CALL + .LBRANCH _IF_END120_STDLIB +_IF_ELSE120_STDLIB: + LOAD 0 ; FIL + LOADC 68 + ADD + LOADI + .LCBRANCHZ _IF_ELSE121_STDLIB + LOAD 0 ; FIL + LOADCP FLUSHFILE + CALL +_IF_ELSE121_STDLIB: +_IF_END121_STDLIB: + LOAD 4 ; POSITION + LOAD 0 ; FIL + LOADC 36 + ADD + LOADI + CMP GT + LOAD 0 ; FIL + LOADI + LOADC 4 + CMP EQ + OR + .LCBRANCHZ _IF_ELSE122_STDLIB + LOAD 0 ; FIL + LOADC 6 + LOADCP FILEERROR + CALL + .LBRANCH _IF_END122_STDLIB +_IF_ELSE122_STDLIB: + LOAD 0 ; FIL + LOADC 28 + ADD + LOAD 4 ; POSITION + STOREI + DROP + LOAD 0 ; FIL + LOADC 60 + ADD + LOAD 4 ; POSITION + LOAD 0 ; FIL + LOADC 64 + ADD + LOADI + LOADCP _MOD + CALL + STOREI + DROP + LOAD 4 ; POSITION + LOAD 0 ; FIL + LOADC 32 + ADD + LOADI + CMP LT + LOAD 4 ; POSITION + LOAD 0 ; FIL + LOADC 32 + ADD + LOADI + LOAD 0 ; FIL + LOADC 64 + ADD + LOADI + ADD + CMP GE + OR + .LCBRANCHZ _IF_ELSE123_STDLIB + LOAD 0 ; FIL + ; ERROR + LOADREG FP + INC 12 + LOADCP READBUF + CALL + LOAD 12 ; ERROR + LOADC 0 + CMP NE + .LCBRANCHZ _IF_ELSE124_STDLIB + LOAD 0 ; FIL + LOAD 12 ; ERROR + LOADCP FILEERROR + CALL +_IF_ELSE124_STDLIB: +_IF_END124_STDLIB: +_IF_ELSE123_STDLIB: +_IF_END123_STDLIB: +_IF_END122_STDLIB: +_IF_END120_STDLIB: + FPADJ 16 + RET + .CPOOL +FILEPOS: + FPADJ -8 + STORE 0 ; FIL + LOAD 0 ; FIL + LOADC 16 + ADD + LOADI + LOADC 0 + CMP EQ + .LCBRANCHZ _IF_ELSE125_STDLIB + LOADC 0 + STORE 4 ; FILEPOS + .LBRANCH _IF_END125_STDLIB +_IF_ELSE125_STDLIB: + LOAD 0 ; FIL + LOADC 28 + ADD + LOADI + STORE 4 ; FILEPOS +_IF_END125_STDLIB: + LOAD 4 ; FILEPOS + FPADJ 8 + RET +FILESIZE: + FPADJ -8 + STORE 0 ; FIL + LOAD 0 ; FIL + LOADC 16 + ADD + LOADI + LOADC 0 + CMP EQ + .LCBRANCHZ _IF_ELSE126_STDLIB + LOADC -1 + STORE 4 ; FILESIZE + .LBRANCH _IF_END126_STDLIB +_IF_ELSE126_STDLIB: + LOAD 0 ; FIL + LOADC 36 + ADD + LOADI + STORE 4 ; FILESIZE +_IF_END126_STDLIB: + LOAD 4 ; FILESIZE + FPADJ 8 + RET +EXTENDFILE: + FPADJ -88 + STORE 4 ; NEWSIZE + STORE 0 ; FIL + ; ENTRY + LOADREG FP + INC 12 + LOADC 64 + LOADCP _CLEARMEM + CALL + LOAD 4 ; NEWSIZE + LOAD 0 ; FIL + LOADC 36 + ADD + LOADI + CMP GT + .LCBRANCHZ _IF_ELSE127_STDLIB + LOAD 4 ; NEWSIZE + LOAD 0 ; FIL + LOADC 48 + ADD + LOADI + LOADC 512 + LOADCP _MUL + CALL + LOADCP _DIV + CALL + LOADC 1 + ADD + STORE 8 ; NEWEXTENTS + LOAD 8 ; NEWEXTENTS + LOAD 0 ; FIL + LOADC 40 + ADD + LOADI + CMP GT + .LCBRANCHZ _IF_ELSE128_STDLIB + LOAD 0 ; FIL + LOADC 24 + ADD + LOADI + LOAD 8 ; NEWEXTENTS + ADD + LOADC 1 + SUB + STORE 76 ; ENDSLOT + LOAD 0 ; FIL + LOADC 24 + ADD + LOADI + LOAD 0 ; FIL + LOADC 40 + ADD + LOADI + ADD + STORE 80 ; I + LOAD 76 ; ENDSLOT +_FOR_START14_STDLIB: + LOAD 80 ; I + OVER + CMP GT + .LCBRANCH _FOR_END14_STDLIB + LOAD 0 ; FIL + LOADC 20 + ADD + LOADI + LOAD 80 ; I + ; ENTRY + LOADREG FP + INC 12 + ; ERROR + LOADREG FP + LOADC 84 + ADD + LOADCP GETDIRSLOT + CALL + LOADC 0 + LOAD 52 ; ENTRY + LOADCP _TESTBIT + CALL + LOADC 0 + CMP EQ + .LCBRANCHZ _IF_ELSE129_STDLIB + LOAD 0 ; FIL + LOADC 7 + LOADCP FILEERROR + CALL + .LBRANCH _FOR_END14_STDLIB + .LBRANCH _IF_END129_STDLIB +_IF_ELSE129_STDLIB: + LOAD 52 ; ENTRY + LOADC 0 + LOADC 0 + LOADCP _SETBIT + CALL + LOADC 3 + LOADCP _SETBIT + CALL + NOT + AND + LOADC 0 + LOADC 5 + LOADCP _SETBIT + CALL + OR + STORE 52 ; ENTRY + LOAD 0 ; FIL + LOADC 20 + ADD + LOADI + LOAD 80 ; I + ; ENTRY + LOADREG FP + INC 12 + ; ERROR + LOADREG FP + LOADC 84 + ADD + LOADCP PUTDIRSLOT + CALL + LOAD 84 ; ERROR + LOADC 0 + CMP NE + .LCBRANCHZ _IF_ELSE130_STDLIB + LOAD 0 ; FIL + LOAD 84 ; ERROR + LOADCP FILEERROR + CALL +_IF_ELSE130_STDLIB: +_IF_END130_STDLIB: +_IF_END129_STDLIB: + LOAD 80 ; I + INC 1 + STORE 80 ; I + .LBRANCH _FOR_START14_STDLIB +_FOR_END14_STDLIB: + DROP +_IF_ELSE128_STDLIB: +_IF_END128_STDLIB: + LOAD 0 ; FIL + INC 4 + LOADI + LOADC 0 + CMP EQ + .LCBRANCHZ _IF_ELSE131_STDLIB + LOAD 0 ; FIL + LOADC 36 + ADD + LOAD 4 ; NEWSIZE + STOREI + DROP + LOAD 0 ; FIL + LOADC 40 + ADD + LOAD 8 ; NEWEXTENTS + STOREI + DROP +_IF_ELSE131_STDLIB: +_IF_END131_STDLIB: +_IF_ELSE127_STDLIB: +_IF_END127_STDLIB: + FPADJ 88 + RET + .CPOOL +WRITEFS: + FPADJ -36 + STORE 8 ; LEN + STORE 4 ; SRCBUF + STORE 0 ; FIL + LOAD 0 ; FIL + LOADC 64 + ADD + LOADI + LOAD 0 ; FIL + LOADC 60 + ADD + LOADI + SUB + STORE 12 ; BUFLEFT + LOAD 8 ; LEN + STORE 16 ; SRCLEFT + LOADC 0 + STORE 20 ; SRCPOS + LOADC 0 + STORE 32 ; ERROR + LOAD 0 ; FIL + LOADI + LOADC 0 + CMP EQ + .LCBRANCHZ _IF_ELSE132_STDLIB + LOAD 0 ; FIL + LOADC 8 + LOADCP FILEERROR + CALL + .LBRANCH _L105ERREXIT_STDLIB +_IF_ELSE132_STDLIB: +_IF_END132_STDLIB: + LOAD 0 ; FIL + LOADC 28 + ADD + LOADI + LOAD 8 ; LEN + ADD + STORE 28 ; NEWPOS + LOAD 28 ; NEWPOS + LOAD 0 ; FIL + LOADC 36 + ADD + LOADI + CMP GT + .LCBRANCHZ _IF_ELSE133_STDLIB + LOAD 0 ; FIL + LOAD 28 ; NEWPOS + LOADCP EXTENDFILE + CALL + LOAD 0 ; FIL + INC 4 + LOADI + LOADC 0 + CMP NE + .LCBRANCHZ _IF_ELSE134_STDLIB + .LBRANCH _L105ERREXIT_STDLIB +_IF_ELSE134_STDLIB: +_IF_END134_STDLIB: +_IF_ELSE133_STDLIB: +_IF_END133_STDLIB: +_WHILE_START13_STDLIB: + LOAD 16 ; SRCLEFT + LOADC 0 + CMP GT + LOAD 32 ; ERROR + LOADC 0 + CMP EQ + AND + .LCBRANCHZ _WHILE_END13_STDLIB + LOAD 0 ; FIL + LOADC 52 + ADD + LOADC 1 + STOREI + DROP + LOAD 0 ; FIL + LOADC 68 + ADD + LOADC 1 + STOREI + DROP + LOAD 16 ; SRCLEFT + LOAD 12 ; BUFLEFT + CMP GT + .LCBRANCHZ _IF_ELSE135_STDLIB + LOAD 0 ; FIL + LOADC 56 + ADD + LOADI + LOAD 0 ; FIL + LOADC 60 + ADD + LOADI + LOAD 4 ; SRCBUF + LOAD 20 ; SRCPOS + LOAD 12 ; BUFLEFT + LOADCP COPYBUF + CALL + LOAD 0 ; FIL + LOADC 60 + ADD + LOADC 0 + STOREI + DROP + LOAD 0 ; FIL + LOADC 28 + ADD + LOAD 0 ; FIL + LOADC 28 + ADD + LOADI + LOAD 12 ; BUFLEFT + ADD + STOREI + DROP + LOAD 16 ; SRCLEFT + LOAD 12 ; BUFLEFT + SUB + STORE 16 ; SRCLEFT + LOAD 20 ; SRCPOS + LOAD 12 ; BUFLEFT + ADD + STORE 20 ; SRCPOS + LOAD 0 ; FIL + LOADC 64 + ADD + LOADI + STORE 12 ; BUFLEFT + .LBRANCH _IF_END135_STDLIB +_IF_ELSE135_STDLIB: + LOAD 0 ; FIL + LOADC 56 + ADD + LOADI + LOAD 0 ; FIL + LOADC 60 + ADD + LOADI + LOAD 4 ; SRCBUF + LOAD 20 ; SRCPOS + LOAD 16 ; SRCLEFT + LOADCP COPYBUF + CALL + LOAD 0 ; FIL + LOADC 60 + ADD + LOAD 0 ; FIL + LOADC 60 + ADD + LOADI + LOAD 16 ; SRCLEFT + ADD + STOREI + DROP + LOAD 0 ; FIL + LOADC 28 + ADD + LOAD 0 ; FIL + LOADC 28 + ADD + LOADI + LOAD 16 ; SRCLEFT + ADD + STOREI + DROP + LOAD 12 ; BUFLEFT + LOAD 16 ; SRCLEFT + SUB + STORE 12 ; BUFLEFT + LOADC 0 + STORE 16 ; SRCLEFT +_IF_END135_STDLIB: + LOAD 0 ; FIL + LOADC 28 + ADD + LOADI + LOAD 0 ; FIL + LOADC 32 + ADD + LOADI + LOAD 0 ; FIL + LOADC 64 + ADD + LOADI + ADD + CMP GE + .LCBRANCHZ _IF_ELSE136_STDLIB + LOAD 0 ; FIL + LOADCP FLUSHFILE + CALL + LOAD 16 ; SRCLEFT + LOAD 0 ; FIL + LOADC 64 + ADD + LOADI + CMP LT + .LCBRANCHZ _IF_ELSE137_STDLIB + LOAD 0 ; FIL + ; ERROR + LOADREG FP + LOADC 32 + ADD + LOADCP READBUF + CALL + .LBRANCH _IF_END137_STDLIB + .CPOOL +_IF_ELSE137_STDLIB: + LOAD 0 ; FIL + LOADC 32 + ADD + LOAD 0 ; FIL + LOADC 32 + ADD + LOADI + LOAD 0 ; FIL + LOADC 64 + ADD + LOADI + ADD + STOREI + DROP +_IF_END137_STDLIB: +_IF_ELSE136_STDLIB: +_IF_END136_STDLIB: + LOAD 32 ; ERROR + LOADC 0 + CMP NE + .LCBRANCHZ _IF_ELSE138_STDLIB + LOAD 0 ; FIL + LOAD 32 ; ERROR + LOADCP FILEERROR + CALL +_IF_ELSE138_STDLIB: +_IF_END138_STDLIB: + .LBRANCH _WHILE_START13_STDLIB +_WHILE_END13_STDLIB: +_L105ERREXIT_STDLIB: + FPADJ 36 + RET +FINDFILE: + FPADJ -36 + STORE 12 ; ERROR + STORE 8 ; DIRSLOT + STORE 4 ; NAME + STORE 0 ; VOLID + LOADC -1 + STORE 16 ; FINDFILE + LOADCP VOLUMETABLE ; VOLUMETABLE + LOAD 0 ; VOLID + DEC 1 + DUP + LOADC 32 + LOADCP _BOUNDSCHECK + CALL + LOADC 96 + LOADCP _MULU + CALL + ADD + LOADREG FP + DEC 4 + SWAP + STOREI + DROP + LOADREG FP + DEC 4 + LOADI + LOADC 56 + ADD + LOADI + STORE 24 ; MAXSLOTS + LOADREG FP + DEC 4 + LOADI + LOADC 72 + ADD + LOADI + STORE 20 ; SLOTNO + LOADC 0 + STORE 28 ; DONE + LOADC 0 + STORE 32 ; FOUND +_REPEAT_START10_STDLIB: + LOAD 0 ; VOLID + LOAD 20 ; SLOTNO + LOAD 8 ; DIRSLOT + LOAD 12 ; ERROR + FPADJ -4 + LOADCP GETDIRSLOT + CALL + FPADJ 4 + LOADC 2 + LOAD 8 ; DIRSLOT + LOADC 40 + ADD + LOADI + LOADCP _TESTBIT + CALL + LOADC 0 + CMP EQ + LOADC 4 + LOAD 8 ; DIRSLOT + LOADC 40 + ADD + LOADI + LOADCP _TESTBIT + CALL + AND + LOAD 4 ; NAME + LOAD 8 ; DIRSLOT + FPADJ -4 + LOADCP _CMPSTRING + CALL + FPADJ 4 + AND + .LCBRANCHZ _IF_ELSE139_STDLIB + LOAD 20 ; SLOTNO + STORE 16 ; FINDFILE + LOADC 1 + STORE 28 ; DONE + LOADC 1 + STORE 32 ; FOUND +_IF_ELSE139_STDLIB: +_IF_END139_STDLIB: + LOADC 3 + LOAD 8 ; DIRSLOT + LOADC 40 + ADD + LOADI + LOADCP _TESTBIT + CALL + .LCBRANCHZ _IF_ELSE140_STDLIB + LOADC 1 + STORE 28 ; DONE +_IF_ELSE140_STDLIB: +_IF_END140_STDLIB: + LOAD 20 ; SLOTNO + LOADC 1 + ADD + STORE 20 ; SLOTNO + LOAD 28 ; DONE + LOAD 20 ; SLOTNO + LOAD 24 ; MAXSLOTS + CMP GE + OR + LOAD 12 ; ERROR + LOADI + LOADC 0 + CMP NE + OR + .LCBRANCHZ _REPEAT_START10_STDLIB +_REPEAT_END10_STDLIB: + LOAD 12 ; ERROR + LOADI + LOADC 0 + CMP EQ + LOAD 32 ; FOUND + LOADC 0 + CMP EQ + AND + .LCBRANCHZ _IF_ELSE141_STDLIB + LOAD 12 ; ERROR + LOADC 1 + STOREI + DROP +_IF_ELSE141_STDLIB: +_IF_END141_STDLIB: + LOAD 16 ; FINDFILE + FPADJ 36 + RET +OPENFILE: + FPADJ -24 + STORE 16 ; MODE + STORE 12 ; AFILE + STORE 8 ; DIRSLOT + STORE 4 ; SLOTNO + STORE 0 ; VOLID + LOADCP VOLUMETABLE ; VOLUMETABLE + LOAD 0 ; VOLID + DEC 1 + DUP + LOADC 32 + LOADCP _BOUNDSCHECK + CALL + LOADC 96 + LOADCP _MULU + CALL + ADD + LOADC 52 + ADD + LOADI + STORE 20 ; EXTENTSIZE + LOAD 12 ; AFILE + LOADC 16 + ADD + LOADC 1 + STOREI + DROP + LOAD 12 ; AFILE + LOAD 16 ; MODE + STOREI + DROP + LOAD 12 ; AFILE + LOADC 56 + ADD + LOADC 4095 + INC 1 + LOADCP _MEM_ALLOC + CALL + LOADCP _CHECK_ALLOC + CALL + STOREI + DROP + LOAD 12 ; AFILE + LOADC 60 + ADD + LOADC 0 + STOREI + DROP + LOAD 12 ; AFILE + LOADC 64 + ADD + LOADC 4095 + INC 1 + STOREI + DROP + LOAD 12 ; AFILE + LOADC 68 + ADD + LOADC 0 + STOREI + DROP + LOAD 12 ; AFILE + LOADC 52 + ADD + LOADC 0 + STOREI + DROP + LOAD 12 ; AFILE + INC 4 + LOADC 0 + STOREI + DROP + LOAD 12 ; AFILE + INC 8 + LOADC 0 + STOREI + DROP + LOAD 12 ; AFILE + LOADC 20 + ADD + LOAD 0 ; VOLID + STOREI + DROP + LOAD 12 ; AFILE + LOADC 24 + ADD + LOAD 4 ; SLOTNO + STOREI + DROP + LOAD 12 ; AFILE + LOADC 28 + ADD + LOADC 0 + STOREI + DROP + LOAD 12 ; AFILE + LOADC 32 + ADD + LOADC 1 + STOREI + DROP + LOAD 12 ; AFILE + LOADC 36 + ADD + LOAD 8 ; DIRSLOT + LOADC 44 + ADD + LOADI + STOREI + DROP + LOAD 12 ; AFILE + LOADC 40 + ADD + LOAD 8 ; DIRSLOT + LOADC 44 + ADD + LOADI + LOAD 20 ; EXTENTSIZE + LOADCP _DIV + CALL + LOADC 1 + ADD + STOREI + DROP + LOAD 12 ; AFILE + LOADC 44 + ADD + LOADC 8 + STOREI + DROP + LOAD 12 ; AFILE + LOADC 48 + ADD + LOAD 20 ; EXTENTSIZE + LOADC 512 + LOADCP _DIV + CALL + STOREI + DROP + LOAD 12 ; AFILE + LOADC 0 + LOADCP SEEK + CALL + FPADJ 24 + RET + .CPOOL +UPDATEDIRSLOT: + FPADJ -72 + STORE 0 ; AFILE + ; DIRS + LOADREG FP + INC 4 + LOADC 64 + LOADCP _CLEARMEM + CALL + LOAD 0 ; AFILE + LOADC 20 + ADD + LOADI + LOAD 0 ; AFILE + LOADC 24 + ADD + LOADI + ; DIRS + LOADREG FP + INC 4 + ; ERROR + LOADREG FP + LOADC 68 + ADD + LOADCP GETDIRSLOT + CALL + LOAD 68 ; ERROR + LOADC 0 + CMP EQ + .LCBRANCHZ _IF_ELSE142_STDLIB + LOAD 0 ; AFILE + LOADC 36 + ADD + LOADI + STORE 48 ; DIRS + LOADCP GETCURTIMESTAMP + CALL + STORE 56 ; DIRS + LOAD 0 ; AFILE + LOADC 20 + ADD + LOADI + LOAD 0 ; AFILE + LOADC 24 + ADD + LOADI + ; DIRS + LOADREG FP + INC 4 + ; ERROR + LOADREG FP + LOADC 68 + ADD + LOADCP PUTDIRSLOT + CALL +_IF_ELSE142_STDLIB: +_IF_END142_STDLIB: + LOAD 0 ; AFILE + LOAD 68 ; ERROR + LOADCP FILEERROR + CALL + FPADJ 72 + RET +CLOSE: + FPADJ -4 + STORE 0 ; AFILE + LOAD 0 ; AFILE + LOADC 16 + ADD + LOADI + LOADC 1 + CMP EQ + .LCBRANCHZ _IF_ELSE143_STDLIB + LOAD 0 ; AFILE + LOADC 68 + ADD + LOADI + .LCBRANCHZ _IF_ELSE144_STDLIB + LOAD 0 ; AFILE + LOADCP FLUSHFILE + CALL +_IF_ELSE144_STDLIB: +_IF_END144_STDLIB: + LOAD 0 ; AFILE + INC 4 + LOADI + LOADC 0 + CMP EQ + .LCBRANCHZ _IF_ELSE145_STDLIB + LOAD 0 ; AFILE + LOADC 5 + LOADCP FILEERROR + CALL + LOAD 0 ; AFILE + LOADC 56 + ADD + LOADI + LOADCP _MEM_FREE + CALL + LOAD 0 ; AFILE + LOADC 56 + ADD + LOADC 0 + STOREI + DROP + LOAD 0 ; AFILE + LOADC 52 + ADD + LOADI + .LCBRANCHZ _IF_ELSE146_STDLIB + LOAD 0 ; AFILE + LOADCP UPDATEDIRSLOT + CALL +_IF_ELSE146_STDLIB: +_IF_END146_STDLIB: +_IF_ELSE145_STDLIB: +_IF_END145_STDLIB: + LOAD 0 ; AFILE + LOADC 20 + ADD + LOADI + LOADCP CLOSEVOLUMEID + CALL +_IF_ELSE143_STDLIB: +_IF_END143_STDLIB: + FPADJ 4 + RET +DELETEFILE: + FPADJ -16 + STORE 12 ; ERROR + STORE 8 ; DIRSLOT + STORE 4 ; SLOTNO + STORE 0 ; VOLID + LOAD 8 ; DIRSLOT + LOADC 40 + ADD + LOAD 8 ; DIRSLOT + LOADC 40 + ADD + LOADI + LOADC 0 + LOADC 4 + LOADCP _SETBIT + CALL + NOT + AND + LOADC 0 + LOADC 2 + LOADCP _SETBIT + CALL + OR + STOREI + DROP + LOAD 0 ; VOLID + LOAD 4 ; SLOTNO + LOAD 8 ; DIRSLOT + LOAD 12 ; ERROR + LOADCP PUTDIRSLOT + CALL + FPADJ 16 + RET +CREATEFILE: + FPADJ -144 + STORE 56 ; ERROR + STORE 52 ; DIRSLOT + STORE 48 ; SLOTNO + STORE 44 ; OVERWRITE + ; NAME + LOADREG FP + INC 4 + SWAP + LOADC 32 + LOADCP _INITSTRINGFROM + CALL + STORE 0 ; VOLID + ; OLDDIRSLOT + LOADREG FP + LOADC 72 + ADD + LOADC 64 + LOADCP _CLEARMEM + CALL + LOADC 0 + STORE 60 ; GENERATION + LOAD 0 ; VOLID + ; NAME + LOADREG FP + INC 4 + ; OLDDIRSLOT + LOADREG FP + LOADC 72 + ADD + LOAD 56 ; ERROR + LOADCP FINDFILE + CALL + STORE 68 ; OLDSLOTNO + LOAD 44 ; OVERWRITE + LOADC 0 + CMP EQ + LOAD 68 ; OLDSLOTNO + LOADC 0 + CMP GT + AND + .LCBRANCHZ _IF_ELSE147_STDLIB + LOAD 56 ; ERROR + LOADC 4 + STOREI + DROP + LOAD 48 ; SLOTNO + LOADC -1 + STOREI + DROP + .LBRANCH _IF_END147_STDLIB +_IF_ELSE147_STDLIB: + LOADCP GETCURTIMESTAMP + CALL + STORE 140 ; NOWTS + LOAD 44 ; OVERWRITE + LOAD 68 ; OLDSLOTNO + LOADC 0 + CMP GT + AND + .LCBRANCHZ _IF_ELSE148_STDLIB + LOAD 128 ; OLDDIRSLOT + LOADC 1 + ADD + STORE 60 ; GENERATION + LOAD 120 ; OLDDIRSLOT + STORE 136 ; CREATETS + .LBRANCH _IF_END148_STDLIB + .CPOOL +_IF_ELSE148_STDLIB: + LOAD 140 ; NOWTS + STORE 136 ; CREATETS +_IF_END148_STDLIB: + LOAD 48 ; SLOTNO + LOAD 0 ; VOLID + LOAD 56 ; ERROR + LOADCP FINDDIRSLOT + CALL + STOREI + DROP + LOAD 48 ; SLOTNO + LOADI + LOADC 0 + CMP LE + .LCBRANCHZ _IF_ELSE149_STDLIB + LOAD 56 ; ERROR + LOADC 7 + STOREI + DROP + .LBRANCH _IF_END149_STDLIB +_IF_ELSE149_STDLIB: + LOAD 48 ; SLOTNO + LOADI + LOADC 0 + CMP GT + LOAD 56 ; ERROR + LOADI + LOADC 0 + CMP EQ + AND + .LCBRANCHZ _IF_ELSE150_STDLIB + LOAD 0 ; VOLID + LOAD 48 ; SLOTNO + LOADI + LOAD 52 ; DIRSLOT + LOAD 56 ; ERROR + LOADCP GETDIRSLOT + CALL + LOAD 52 ; DIRSLOT + ; NAME + LOADREG FP + INC 4 + LOADC 32 + LOADCP _INITSTRINGFROM + CALL + LOAD 52 ; DIRSLOT + LOADC 40 + ADD + LOADC 0 + LOADC 4 + LOADCP _SETBIT + CALL + STOREI + DROP + LOAD 52 ; DIRSLOT + LOADC 44 + ADD + LOADC 0 + STOREI + DROP + LOAD 52 ; DIRSLOT + LOADC 56 + ADD + LOAD 60 ; GENERATION + STOREI + DROP + LOAD 52 ; DIRSLOT + LOADC 60 + ADD + LOADC 0 + STOREI + DROP + LOAD 52 ; DIRSLOT + LOADC 52 + ADD + LOAD 140 ; NOWTS + STOREI + DROP + LOAD 52 ; DIRSLOT + LOADC 48 + ADD + LOAD 136 ; CREATETS + STOREI + DROP + LOAD 0 ; VOLID + LOAD 48 ; SLOTNO + LOADI + LOAD 52 ; DIRSLOT + LOAD 56 ; ERROR + LOADCP PUTDIRSLOT + CALL + LOAD 44 ; OVERWRITE + LOAD 68 ; OLDSLOTNO + LOADC 0 + CMP GT + AND + .LCBRANCHZ _IF_ELSE151_STDLIB + LOAD 0 ; VOLID + LOAD 68 ; OLDSLOTNO + ; OLDDIRSLOT + LOADREG FP + LOADC 72 + ADD + LOAD 56 ; ERROR + LOADCP DELETEFILE + CALL +_IF_ELSE151_STDLIB: +_IF_END151_STDLIB: +_IF_ELSE150_STDLIB: +_IF_END150_STDLIB: +_IF_END149_STDLIB: +_IF_END147_STDLIB: + FPADJ 144 + RET +INITDEVICES: + LOADCP CARDCHANGED + CALL + .LCBRANCHZ _IF_ELSE152_STDLIB + LOADCP DEVICESINITIALIZED ; DEVICESINITIALIZED + LOADC 0 + STOREI + DROP +_IF_ELSE152_STDLIB: +_IF_END152_STDLIB: + LOADCP DEVICESINITIALIZED ; DEVICESINITIALIZED + LOADI + LOADC 0 + CMP EQ + .LCBRANCHZ _IF_ELSE153_STDLIB + LOADCP DEFAULTVOLUMEID ; DEFAULTVOLUMEID + LOADC 0 + STOREI + DROP + LOADCP INITSDCARD + CALL + LOADCP VOLUMECOUNT ; VOLUMECOUNT + LOADC 0 + STOREI + DROP + LOADC 0 + LOADCP READPARTITIONS + CALL + LOADCP DEVICESINITIALIZED ; DEVICESINITIALIZED + LOADC 1 + STOREI + DROP + LOADCP DEFAULTVOLUME ; DEFAULTVOLUME + LOADCP LENGTH + CALL + LOADC 0 + CMP GT + .LCBRANCHZ _IF_ELSE154_STDLIB + LOADCP DEFAULTVOLUMEID ; DEFAULTVOLUMEID + LOADCP DEFAULTVOLUME ; DEFAULTVOLUME + LOADCP FINDVOLUME + CALL + STOREI + DROP +_IF_ELSE154_STDLIB: +_IF_END154_STDLIB: + LOADCP DEFAULTVOLUMEID ; DEFAULTVOLUMEID + LOADI + LOADC 0 + CMP EQ + LOADCP VOLUMECOUNT ; VOLUMECOUNT + LOADI + LOADC 0 + CMP GT + AND + .LCBRANCHZ _IF_ELSE155_STDLIB + LOADCP DEFAULTVOLUMEID ; DEFAULTVOLUMEID + LOADC 1 + STOREI + DROP +_IF_ELSE155_STDLIB: +_IF_END155_STDLIB: +_IF_ELSE153_STDLIB: +_IF_END153_STDLIB: + RET +READDIRNEXT: + FPADJ -24 + STORE 12 ; ERROR + STORE 8 ; DIRSLOT + STORE 4 ; INDEX + STORE 0 ; VOLID + LOADCP VOLUMETABLE ; VOLUMETABLE + LOAD 0 ; VOLID + DEC 1 + DUP + LOADC 32 + LOADCP _BOUNDSCHECK + CALL + LOADC 96 + LOADCP _MULU + CALL + ADD + LOADC 56 + ADD + LOADI + LOADC 1 + SUB + STORE 16 ; LASTSLOT + LOADC 0 + STORE 20 ; FOUND +_REPEAT_START11_STDLIB: + LOAD 0 ; VOLID + LOAD 4 ; INDEX + LOADI + LOAD 8 ; DIRSLOT + LOAD 12 ; ERROR + LOADCP GETDIRSLOT + CALL + LOAD 4 ; INDEX + LOAD 4 ; INDEX + LOADI + LOADC 1 + ADD + STOREI + DROP + LOADC 4 + LOAD 8 ; DIRSLOT + LOADC 40 + ADD + LOADI + LOADCP _TESTBIT + CALL + STORE 20 ; FOUND + LOAD 20 ; FOUND + LOADC 3 + LOAD 8 ; DIRSLOT + LOADC 40 + ADD + LOADI + LOADCP _TESTBIT + CALL + OR + LOAD 4 ; INDEX + LOADI + LOAD 16 ; LASTSLOT + CMP EQ + OR + LOAD 12 ; ERROR + LOADI + LOADC 0 + CMP NE + OR + .LCBRANCHZ _REPEAT_START11_STDLIB +_REPEAT_END11_STDLIB: + LOAD 20 ; FOUND + LOADC 0 + CMP EQ + .LCBRANCHZ _IF_ELSE156_STDLIB + LOAD 4 ; INDEX + LOADC -1 + STOREI + DROP +_IF_ELSE156_STDLIB: +_IF_END156_STDLIB: + FPADJ 24 + RET + .CPOOL +READDIRFIRST: + FPADJ -16 + STORE 12 ; ERROR + STORE 8 ; DIRSLOT + STORE 4 ; INDEX + STORE 0 ; VOLID + LOADCP INITDEVICES + CALL + LOAD 4 ; INDEX + LOADCP VOLUMETABLE ; VOLUMETABLE + LOAD 0 ; VOLID + DEC 1 + DUP + LOADC 32 + LOADCP _BOUNDSCHECK + CALL + LOADC 96 + LOADCP _MULU + CALL + ADD + LOADC 72 + ADD + LOADI + STOREI + DROP + LOAD 0 ; VOLID + LOAD 4 ; INDEX + LOAD 8 ; DIRSLOT + LOAD 12 ; ERROR + LOADCP READDIRNEXT + CALL + FPADJ 16 + RET +CHARPOS: + FPADJ -20 + STORE 4 ; S + STORE 0 ; SEARCHCHAR + LOADC 0 + STORE 8 ; CHARPOS + LOADC 1 + STORE 16 ; P + LOAD 4 ; S + DUP + LOADI + SWAP + INC 8 +_FOR_START15_STDLIB: + OVER + .LCBRANCHZ _FOR_END15_STDLIB + DUP + LOADI.S1.X2Y + BSEL + STORE 12 ; C + LOAD 12 ; C + LOAD 0 ; SEARCHCHAR + CMP EQ + .LCBRANCHZ _IF_ELSE157_STDLIB + LOAD 16 ; P + STORE 8 ; CHARPOS + .LBRANCH _FOR_END15_STDLIB +_IF_ELSE157_STDLIB: +_IF_END157_STDLIB: + LOAD 16 ; P + LOADC 1 + ADD + STORE 16 ; P + INC 1 + SWAP + DEC 1 + SWAP + .LBRANCH _FOR_START15_STDLIB +_FOR_END15_STDLIB: + DROP + DROP + LOAD 8 ; CHARPOS + FPADJ 20 + RET +OPENVOLPATH: + FPADJ -144 + STORE 92 ; ERROR + STORE 88 ; DIRS + STORE 84 ; SLOTNO + STORE 80 ; FNAME + STORE 76 ; VOLID + ; PATH + LOADREG FP + SWAP + LOADC 68 + LOADCP _INITSTRINGFROM + CALL + LOADC 32 + ; VOLNAME + LOADREG FP + LOADC 104 + ADD + LOADCP _INITSTRINGF + CALL + LOADCP INITDEVICES + CALL + LOAD 84 ; SLOTNO + LOADC 0 + STOREI + DROP + LOAD 92 ; ERROR + LOADC 0 + STOREI + DROP + LOAD 76 ; VOLID + LOADC 0 + STOREI + DROP + ; PATH + LOADREG FP + LOADC 1 + LOADCP _INDEXSTRING + CALL + LOADI.S1.X2Y + BSEL + LOADC 35 + CMP EQ + .LCBRANCHZ _IF_ELSE158_STDLIB + LOADC 58 + ; PATH + LOADREG FP + LOADCP CHARPOS + CALL + STORE 100 ; SEPARATORPOS + LOAD 100 ; SEPARATORPOS + LOADC 0 + CMP GT + .LCBRANCHZ _IF_ELSE159_STDLIB + ; VOLNAME + LOADREG FP + LOADC 104 + ADD + ; PATH + LOADREG FP + LOADC 2 + LOAD 100 ; SEPARATORPOS + LOADC 2 + SUB + LOADC 80 + LOADREG FP + LOADC 88 + SUB + LOADCP _INITSTRINGF + CALL + LOADREG FP + LOADC 88 + SUB + FPADJ -88 + LOADCP COPY + CALL + FPADJ 88 + FPADJ -88 + LOADCP _COPYSTRING + CALL + FPADJ 88 + LOAD 80 ; FNAME + ; PATH + LOADREG FP + LOAD 100 ; SEPARATORPOS + LOADC 1 + ADD + ; PATH + LOADREG FP + LOADCP LENGTH + CALL + LOAD 100 ; SEPARATORPOS + SUB + LOADC 80 + LOADREG FP + LOADC 88 + SUB + LOADCP _INITSTRINGF + CALL + LOADREG FP + LOADC 88 + SUB + FPADJ -88 + LOADCP COPY + CALL + FPADJ 88 + FPADJ -88 + LOADCP _COPYSTRING + CALL + FPADJ 88 + LOAD 76 ; VOLID + ; VOLNAME + LOADREG FP + LOADC 104 + ADD + LOADCP FINDVOLUME + CALL + STOREI + DROP +_IF_ELSE159_STDLIB: +_IF_END159_STDLIB: + .LBRANCH _IF_END158_STDLIB +_IF_ELSE158_STDLIB: + LOAD 76 ; VOLID + LOADCP DEFAULTVOLUMEID ; DEFAULTVOLUMEID + LOADI + STOREI + DROP + LOAD 80 ; FNAME + ; PATH + LOADREG FP + LOADCP _COPYSTRING + CALL +_IF_END158_STDLIB: + LOAD 76 ; VOLID + LOADI + LOADC 0 + CMP GT + .LCBRANCHZ _IF_ELSE160_STDLIB + LOAD 76 ; VOLID + LOADI + LOADCP OPENVOLUMEID + CALL + LOAD 84 ; SLOTNO + LOAD 76 ; VOLID + LOADI + LOAD 80 ; FNAME + LOAD 88 ; DIRS + LOAD 92 ; ERROR + LOADCP FINDFILE + CALL + STOREI + DROP + .LBRANCH _IF_END160_STDLIB + .CPOOL +_IF_ELSE160_STDLIB: + LOAD 92 ; ERROR + LOADC 2 + STOREI + DROP +_IF_END160_STDLIB: + FPADJ 144 + RET +RENAME: + FPADJ -264 + STORE 80 ; ERROR + ; NEWNAME + LOADREG FP + LOADC 40 + ADD + SWAP + LOADC 32 + LOADCP _INITSTRINGFROM + CALL + ; OLDNAME + LOADREG FP + SWAP + LOADC 32 + LOADCP _INITSTRINGFROM + CALL + ; OLDDIRS + LOADREG FP + LOADC 84 + ADD + LOADC 64 + LOADCP _CLEARMEM + CALL + ; NEWDIRS + LOADREG FP + LOADC 148 + ADD + LOADC 64 + LOADCP _CLEARMEM + CALL + LOADC 32 + ; FNAME + LOADREG FP + LOADC 224 + ADD + LOADCP _INITSTRINGF + CALL + LOADC 0 + STORE 212 ; VOLID + ; NEWNAME + LOADREG FP + LOADC 40 + ADD + LOADC 1 + LOADCP _INDEXSTRING + CALL + LOADI.S1.X2Y + BSEL + LOADCP _C_A_8_STDLIB + LOADC 2 + LOADCP _ISINTINARRAY + CALL + .LCBRANCHZ _IF_ELSE161_STDLIB + LOAD 80 ; ERROR + LOADC 3 + STOREI + DROP + .LBRANCH _IF_END161_STDLIB +_IF_ELSE161_STDLIB: + ; OLDNAME + LOADREG FP + ; VOLID + LOADREG FP + LOADC 212 + ADD + ; FNAME + LOADREG FP + LOADC 224 + ADD + ; OLDSLOTNO + LOADREG FP + LOADC 216 + ADD + ; OLDDIRS + LOADREG FP + LOADC 84 + ADD + LOAD 80 ; ERROR + LOADCP OPENVOLPATH + CALL + LOAD 80 ; ERROR + LOADI + LOADC 0 + CMP EQ + .LCBRANCHZ _IF_ELSE162_STDLIB + LOAD 212 ; VOLID + ; NEWNAME + LOADREG FP + LOADC 40 + ADD + ; NEWDIRS + LOADREG FP + LOADC 148 + ADD + LOAD 80 ; ERROR + LOADCP FINDFILE + CALL + STORE 220 ; NEWSLOTNO + LOAD 80 ; ERROR + LOADI + LOADC 1 + CMP EQ + .LCBRANCHZ _IF_ELSE163_STDLIB + LOAD 80 ; ERROR + LOADC 0 + STOREI + DROP + ; OLDDIRS + LOADREG FP + LOADC 84 + ADD + ; NEWNAME + LOADREG FP + LOADC 40 + ADD + LOADC 32 + LOADCP _INITSTRINGFROM + CALL + LOAD 212 ; VOLID + LOAD 216 ; OLDSLOTNO + ; OLDDIRS + LOADREG FP + LOADC 84 + ADD + LOAD 80 ; ERROR + LOADCP PUTDIRSLOT + CALL + .LBRANCH _IF_END163_STDLIB +_IF_ELSE163_STDLIB: + LOAD 80 ; ERROR + LOADI + LOADC 0 + CMP EQ + .LCBRANCHZ _IF_ELSE164_STDLIB + LOAD 80 ; ERROR + LOADC 4 + STOREI + DROP +_IF_ELSE164_STDLIB: +_IF_END164_STDLIB: +_IF_END163_STDLIB: +_IF_ELSE162_STDLIB: +_IF_END162_STDLIB: + LOAD 212 ; VOLID + LOADC 0 + CMP GT + .LCBRANCHZ _IF_ELSE165_STDLIB + LOAD 212 ; VOLID + LOADCP CLOSEVOLUMEID + CALL +_IF_ELSE165_STDLIB: +_IF_END165_STDLIB: +_IF_END161_STDLIB: + FPADJ 264 + RET +ERASE: + FPADJ -192 + STORE 76 ; ERROR + ; NAME + LOADREG FP + SWAP + LOADC 68 + LOADCP _INITSTRINGFROM + CALL + ; DIRS + LOADREG FP + LOADC 80 + ADD + LOADC 64 + LOADCP _CLEARMEM + CALL + LOADC 32 + ; FNAME + LOADREG FP + LOADC 152 + ADD + LOADCP _INITSTRINGF + CALL + LOAD 76 ; ERROR + LOADC 0 + STOREI + DROP + ; NAME + LOADREG FP + LOADC 1 + LOADCP _INDEXSTRING + CALL + LOADI.S1.X2Y + BSEL + LOADC 37 + CMP EQ + .LCBRANCHZ _IF_ELSE166_STDLIB + LOAD 76 ; ERROR + LOADC 3 + STOREI + DROP + .LBRANCH _IF_END166_STDLIB +_IF_ELSE166_STDLIB: + ; NAME + LOADREG FP + ; VOLID + LOADREG FP + LOADC 144 + ADD + ; FNAME + LOADREG FP + LOADC 152 + ADD + ; SLOTNO + LOADREG FP + LOADC 148 + ADD + ; DIRS + LOADREG FP + LOADC 80 + ADD + LOAD 76 ; ERROR + LOADCP OPENVOLPATH + CALL + LOAD 76 ; ERROR + LOADI + LOADC 0 + CMP EQ + .LCBRANCHZ _IF_ELSE167_STDLIB + LOADC 6 + LOAD 120 ; DIRS + LOADCP _TESTBIT + CALL + .LCBRANCHZ _IF_ELSE168_STDLIB + LOAD 76 ; ERROR + LOADC 8 + STOREI + DROP + .LBRANCH _IF_END168_STDLIB + .CPOOL +_IF_ELSE168_STDLIB: + LOAD 144 ; VOLID + LOAD 148 ; SLOTNO + ; DIRS + LOADREG FP + LOADC 80 + ADD + LOAD 76 ; ERROR + LOADCP DELETEFILE + CALL +_IF_END168_STDLIB: +_IF_ELSE167_STDLIB: +_IF_END167_STDLIB: + LOAD 144 ; VOLID + LOADC 0 + CMP GT + .LCBRANCHZ _IF_ELSE169_STDLIB + LOAD 144 ; VOLID + LOADCP CLOSEVOLUMEID + CALL +_IF_ELSE169_STDLIB: +_IF_END169_STDLIB: +_IF_END166_STDLIB: + FPADJ 192 + RET +WRITECHANNEL: + FPADJ -8 + STORE 4 ; ACHAR + STORE 0 ; F + LOAD 4 ; ACHAR + LOADCP CONOUT + CALL + FPADJ 8 + RET +WRITECHANNELW: + FPADJ -8 + STORE 4 ; WORD + STORE 0 ; F + LOAD 4 ; WORD + LOADCP CONOUTW + CALL + FPADJ 8 + RET +ECHOCHANNEL: + FPADJ -8 + STORE 4 ; ACHAR + STORE 0 ; F + LOAD 0 ; F + LOADC 36 + ADD + LOADI + LOADC 0 + CMP EQ + .LCBRANCHZ _IF_ELSE170_STDLIB + LOAD 0 ; F + LOADC 40 + ADD + LOADI + .LCBRANCHZ _IF_ELSE171_STDLIB + LOAD 0 ; F + LOAD 4 ; ACHAR + LOADCP WRITECHANNEL + CALL + .LBRANCH _IF_END171_STDLIB +_IF_ELSE171_STDLIB: + LOAD 4 ; ACHAR + LOADC 8 + CMP NE + LOAD 4 ; ACHAR + LOADC 9 + CMP NE + AND + LOAD 4 ; ACHAR + LOADC 4 + CMP NE + AND + .LCBRANCHZ _IF_ELSE172_STDLIB + LOAD 0 ; F + LOAD 4 ; ACHAR + LOADCP WRITECHANNEL + CALL + LOAD 4 ; ACHAR + LOADC 13 + CMP EQ + .LCBRANCHZ _IF_ELSE173_STDLIB + LOAD 0 ; F + LOADC 10 + LOADCP WRITECHANNEL + CALL +_IF_ELSE173_STDLIB: +_IF_END173_STDLIB: +_IF_ELSE172_STDLIB: +_IF_END172_STDLIB: +_IF_END171_STDLIB: +_IF_ELSE170_STDLIB: +_IF_END170_STDLIB: + FPADJ 8 + RET +READCHANNEL: + FPADJ -12 + STORE 0 ; F + LOAD 0 ; F + LOADC 28 + ADD + LOADI + LOADC 0 + CMP GT + .LCBRANCHZ _IF_ELSE174_STDLIB + LOAD 0 ; F + LOADC 24 + ADD + LOADI + STORE 8 ; ACHAR + LOAD 0 ; F + LOADC 28 + ADD + LOADC 0 + STOREI + DROP + .LBRANCH _IF_END174_STDLIB +_IF_ELSE174_STDLIB: + LOADCP CONIN + CALL + STORE 8 ; ACHAR + LOAD 0 ; F + LOAD 8 ; ACHAR + LOADCP ECHOCHANNEL + CALL +_IF_END174_STDLIB: + LOAD 0 ; F + LOADC 32 + ADD + LOAD 8 ; ACHAR + LOADC 4 + CMP EQ + STOREI + DROP + LOAD 0 ; F + LOADC 44 + ADD + LOADI + LOADC 0 + CMP EQ + LOAD 8 ; ACHAR + LOADC 3 + CMP EQ + AND + .LCBRANCHZ _IF_ELSE175_STDLIB + LOAD 0 ; F + LOADC 11 + LOADCP FILEERROR + CALL + LOAD 0 ; F + LOADCP CHECKERROR + CALL +_IF_ELSE175_STDLIB: +_IF_END175_STDLIB: + LOAD 8 ; ACHAR + STORE 4 ; READCHANNEL + LOAD 4 ; READCHANNEL + FPADJ 12 + RET +FREADCHAR: + FPADJ -12 + STORE 0 ; F + LOAD 0 ; F + LOADC 16 + ADD + LOADI + LOADC 0 + CMP EQ + .LCBRANCHZ _IF_ELSE176_STDLIB + LOAD 0 ; F + LOADCP READCHANNEL + CALL + STORE 4 ; FREADCHAR + .LBRANCH _IF_END176_STDLIB +_IF_ELSE176_STDLIB: + LOAD 0 ; F + LOADCP READFSCHAR + CALL + STORE 4 ; FREADCHAR +_IF_END176_STDLIB: + LOAD 0 ; F + INC 12 + LOAD 4 ; FREADCHAR + LOADC 13 + CMP EQ + LOAD 4 ; FREADCHAR + LOADC 10 + CMP EQ + OR + STOREI + DROP + LOAD 4 ; FREADCHAR + FPADJ 12 + RET +FWRITECHAR: + FPADJ -8 + STORE 4 ; F + STORE 0 ; ACHAR + LOAD 4 ; F + LOADC 16 + ADD + LOADI + LOADC 0 + CMP EQ + .LCBRANCHZ _IF_ELSE177_STDLIB + LOAD 4 ; F + LOAD 0 ; ACHAR + LOADCP WRITECHANNEL + CALL + .LBRANCH _IF_END177_STDLIB + .CPOOL +_IF_ELSE177_STDLIB: + LOAD 4 ; F + LOAD 0 ; ACHAR + LOADCP WRITEFSCHAR + CALL +_IF_END177_STDLIB: + FPADJ 8 + RET +FWRITESTRING: + FPADJ -24 + STORE 8 ; W + STORE 4 ; F + STORE 0 ; ASTRING + LOAD 8 ; W + LOAD 0 ; ASTRING + LOADCP LENGTH + CALL + SUB + STORE 16 ; MISSING + LOAD 16 ; MISSING + LOADC 0 + CMP GT + .LCBRANCHZ _IF_ELSE178_STDLIB + LOADC 1 + STORE 20 ; I + LOAD 16 ; MISSING +_FOR_START16_STDLIB: + LOAD 20 ; I + OVER + CMP GT + .LCBRANCH _FOR_END16_STDLIB + LOADC 32 + LOAD 4 ; F + LOADCP FWRITECHAR + CALL + LOAD 20 ; I + INC 1 + STORE 20 ; I + .LBRANCH _FOR_START16_STDLIB +_FOR_END16_STDLIB: + DROP +_IF_ELSE178_STDLIB: +_IF_END178_STDLIB: + LOAD 4 ; F + LOADC 16 + ADD + LOADI + LOADC 0 + CMP EQ + .LCBRANCHZ _IF_ELSE179_STDLIB + LOAD 0 ; ASTRING + DUP + LOADI + SWAP + INC 8 +_FOR_START17_STDLIB: + OVER + .LCBRANCHZ _FOR_END17_STDLIB + DUP + LOADI.S1.X2Y + BSEL + STORE 12 ; CH + LOAD 4 ; F + LOAD 12 ; CH + LOADCP WRITECHANNEL + CALL + INC 1 + SWAP + DEC 1 + SWAP + .LBRANCH _FOR_START17_STDLIB +_FOR_END17_STDLIB: + DROP + DROP + .LBRANCH _IF_END179_STDLIB +_IF_ELSE179_STDLIB: + LOAD 4 ; F + LOAD 0 ; ASTRING + LOADCP WRITEFSSTRING + CALL +_IF_END179_STDLIB: + FPADJ 24 + RET +FWRITEINT: + FPADJ -32 + STORE 8 ; W + STORE 4 ; F + STORE 0 ; V + LOADC 12 + ; RBUF + LOADREG FP + INC 12 + LOADCP _INITSTRINGF + CALL + LOAD 0 ; V + LOADC 0 + ; RBUF + LOADREG FP + INC 12 + LOADCP INTSTR + CALL + ; RBUF + LOADREG FP + INC 12 + LOAD 4 ; F + LOAD 8 ; W + LOADCP FWRITESTRING + CALL + FPADJ 32 + RET +FWRITEREAL: + FPADJ -72 + STORE 12 ; D + STORE 8 ; W + STORE 4 ; F + STORE 0 ; V + LOADC 48 + ; RBUF + LOADREG FP + LOADC 16 + ADD + LOADCP _INITSTRINGF + CALL + LOAD 0 ; V + LOAD 8 ; W + LOAD 12 ; D + ; RBUF + LOADREG FP + LOADC 16 + ADD + LOADCP REALSTR + CALL + ; RBUF + LOADREG FP + LOADC 16 + ADD + LOAD 4 ; F + LOAD 8 ; W + LOADCP FWRITESTRING + CALL + FPADJ 72 + RET +FWRITEWORDS: + FPADJ -12 + STORE 8 ; SIZE + STORE 4 ; F + STORE 0 ; WORDS + LOAD 4 ; F + LOADC 16 + ADD + LOADI + LOADC 1 + CMP EQ + .LCBRANCHZ _IF_ELSE180_STDLIB + LOAD 4 ; F + LOAD 0 ; WORDS + LOAD 8 ; SIZE + LOADCP WRITEFS + CALL + .LBRANCH _IF_END180_STDLIB +_IF_ELSE180_STDLIB: + LOAD 4 ; F + LOAD 0 ; WORDS + LOAD 8 ; SIZE + LOADC 2 + LOADCP _SHRM + CALL + LOADCP WRITECHANWORDS + CALL +_IF_END180_STDLIB: + FPADJ 12 + RET +FREADWORDS: + FPADJ -20 + STORE 8 ; SIZE + STORE 4 ; F + STORE 0 ; WORDS + LOAD 4 ; F + LOADC 16 + ADD + LOADI + LOADC 1 + CMP EQ + .LCBRANCHZ _IF_ELSE181_STDLIB + LOAD 4 ; F + LOAD 0 ; WORDS + LOAD 8 ; SIZE + LOADCP READFS + CALL + .LBRANCH _IF_END181_STDLIB +_IF_ELSE181_STDLIB: + LOAD 4 ; F + LOAD 0 ; WORDS + LOAD 8 ; SIZE + LOADC 2 + LOADCP _SHRM + CALL + LOADCP READCHANWORDS + CALL +_IF_END181_STDLIB: + FPADJ 20 + RET +PUSHBACK: + FPADJ -8 + STORE 4 ; ACHAR + STORE 0 ; AFILE + LOAD 0 ; AFILE + LOADC 16 + ADD + LOADI + LOADC 1 + CMP EQ + .LCBRANCHZ _IF_ELSE182_STDLIB + LOAD 0 ; AFILE + LOAD 0 ; AFILE + LOADC 28 + ADD + LOADI + LOADC 1 + SUB + LOADCP SEEK + CALL + .LBRANCH _IF_END182_STDLIB + .CPOOL +_IF_ELSE182_STDLIB: + LOAD 0 ; AFILE + LOADC 24 + ADD + LOAD 4 ; ACHAR + STOREI + DROP + LOAD 0 ; AFILE + LOADC 28 + ADD + LOADC 1 + STOREI + DROP +_IF_END182_STDLIB: + FPADJ 8 + RET +OPENCHANNEL: + FPADJ -52 + STORE 48 ; ERROR + STORE 44 ; MODE + STORE 40 ; F + ; NAME + LOADREG FP + SWAP + LOADC 32 + LOADCP _INITSTRINGFROM + CALL + LOAD 40 ; F + LOADC 16 + ADD + LOADC 0 + STOREI + DROP + LOAD 40 ; F + LOAD 44 ; MODE + STOREI + DROP + LOAD 40 ; F + LOADC 28 + ADD + LOADC 0 + STOREI + DROP + LOAD 40 ; F + LOADC 32 + ADD + LOADC 0 + STOREI + DROP + LOAD 40 ; F + LOADC 36 + ADD + LOADC 0 + STOREI + DROP + LOAD 40 ; F + LOADC 40 + ADD + LOADC 0 + STOREI + DROP + LOAD 40 ; F + LOADC 44 + ADD + LOADC 0 + STOREI + DROP + ; NAME + LOADREG FP + LOADCP _C_S_10_STDLIB + LOADCP _CMPSTRING + CALL + .LCBRANCHZ _IF_ELSE183_STDLIB + LOAD 40 ; F + LOADC 20 + ADD + LOADC 0 + STOREI + DROP + .LBRANCH _IF_END183_STDLIB +_IF_ELSE183_STDLIB: + ; NAME + LOADREG FP + LOADCP _C_S_11_STDLIB + LOADCP _CMPSTRING + CALL + .LCBRANCHZ _IF_ELSE184_STDLIB + LOAD 40 ; F + LOADC 20 + ADD + LOADC 0 + STOREI + DROP + LOAD 40 ; F + LOADC 36 + ADD + LOADC 1 + STOREI + DROP + LOAD 40 ; F + LOADC 40 + ADD + LOADC 1 + STOREI + DROP + .LBRANCH _IF_END184_STDLIB +_IF_ELSE184_STDLIB: + ; NAME + LOADREG FP + LOADCP _C_S_12_STDLIB + LOADCP _CMPSTRING + CALL + .LCBRANCHZ _IF_ELSE185_STDLIB + LOAD 40 ; F + LOADC 20 + ADD + LOADC 0 + STOREI + DROP + LOAD 40 ; F + LOADC 36 + ADD + LOADC 1 + STOREI + DROP + LOAD 40 ; F + LOADC 40 + ADD + LOADC 1 + STOREI + DROP + LOAD 40 ; F + LOADC 44 + ADD + LOADC 1 + STOREI + DROP + .LBRANCH _IF_END185_STDLIB +_IF_ELSE185_STDLIB: + LOAD 48 ; ERROR + LOADC 1 + STOREI + DROP +_IF_END185_STDLIB: +_IF_END184_STDLIB: +_IF_END183_STDLIB: + FPADJ 52 + RET +OPEN: + FPADJ -212 + STORE 80 ; MODE + ; NAME + LOADREG FP + INC 4 + SWAP + LOADC 68 + LOADCP _INITSTRINGFROM + CALL + STORE 0 ; F + ; DIRS + LOADREG FP + LOADC 88 + ADD + LOADC 64 + LOADCP _CLEARMEM + CALL + LOADC 32 + ; FNAME + LOADREG FP + LOADC 172 + ADD + LOADCP _INITSTRINGF + CALL + ; NAME + LOADREG FP + INC 4 + LOADC 1 + LOADCP _INDEXSTRING + CALL + LOADI.S1.X2Y + BSEL + LOADC 37 + CMP EQ + .LCBRANCHZ _IF_ELSE186_STDLIB + ; NAME + LOADREG FP + INC 4 + LOAD 0 ; F + LOAD 80 ; MODE + ; ERROR + LOADREG FP + LOADC 84 + ADD + LOADCP OPENCHANNEL + CALL + .LBRANCH _IF_END186_STDLIB +_IF_ELSE186_STDLIB: + LOADC 0 + STORE 156 ; VOLID + LOAD 80 ; MODE + LOADC 1 + CMP EQ + STORE 160 ; EXCLUSIVE + LOAD 80 ; MODE + LOADC 3 + CMP EQ + STORE 164 ; OVERWRITE + LOAD 80 ; MODE + LOADC 1 + CMP EQ + LOAD 80 ; MODE + LOADC 3 + CMP EQ + OR + LOAD 80 ; MODE + LOADC 4 + CMP EQ + OR + STORE 168 ; CREATEMISSING + ; NAME + LOADREG FP + INC 4 + ; VOLID + LOADREG FP + LOADC 156 + ADD + ; FNAME + LOADREG FP + LOADC 172 + ADD + ; SLOTNO + LOADREG FP + LOADC 152 + ADD + ; DIRS + LOADREG FP + LOADC 88 + ADD + ; ERROR + LOADREG FP + LOADC 84 + ADD + LOADCP OPENVOLPATH + CALL + LOAD 84 ; ERROR + LOADC 0 + CMP EQ + LOAD 160 ; EXCLUSIVE + AND + .LCBRANCHZ _IF_ELSE187_STDLIB + LOAD 0 ; F + LOADC 4 + LOADCP FILEERROR + CALL + LOADC 4 + STORE 84 ; ERROR +_IF_ELSE187_STDLIB: +_IF_END187_STDLIB: + LOAD 84 ; ERROR + LOADC 1 + CMP EQ + LOAD 168 ; CREATEMISSING + AND + LOAD 84 ; ERROR + LOADC 0 + CMP EQ + LOAD 164 ; OVERWRITE + AND + OR + .LCBRANCHZ _IF_ELSE188_STDLIB + LOAD 156 ; VOLID + ; FNAME + LOADREG FP + LOADC 172 + ADD + LOAD 164 ; OVERWRITE + ; SLOTNO + LOADREG FP + LOADC 152 + ADD + ; DIRS + LOADREG FP + LOADC 88 + ADD + ; ERROR + LOADREG FP + LOADC 84 + ADD + LOADCP CREATEFILE + CALL +_IF_ELSE188_STDLIB: +_IF_END188_STDLIB: + LOAD 84 ; ERROR + LOADC 0 + CMP EQ + .LCBRANCHZ _IF_ELSE189_STDLIB + LOAD 156 ; VOLID + LOAD 152 ; SLOTNO + ; DIRS + LOADREG FP + LOADC 88 + ADD + LOAD 0 ; F + LOAD 80 ; MODE + LOADCP OPENFILE + CALL + LOAD 80 ; MODE + LOADC 4 + CMP EQ + .LCBRANCHZ _IF_ELSE190_STDLIB + LOAD 0 ; F + LOAD 0 ; F + LOADC 36 + ADD + LOADI + LOADCP SEEK + CALL +_IF_ELSE190_STDLIB: +_IF_END190_STDLIB: +_IF_ELSE189_STDLIB: +_IF_END189_STDLIB: + LOAD 84 ; ERROR + LOADC 0 + CMP NE + LOAD 156 ; VOLID + LOADC 0 + CMP GT + AND + .LCBRANCHZ _IF_ELSE191_STDLIB + LOAD 156 ; VOLID + LOADCP CLOSEVOLUMEID + CALL +_IF_ELSE191_STDLIB: +_IF_END191_STDLIB: + LOAD 84 ; ERROR + LOADC 0 + CMP NE + .LCBRANCHZ _IF_ELSE192_STDLIB + LOAD 0 ; F + LOAD 84 ; ERROR + LOADCP FILEERROR + CALL +_IF_ELSE192_STDLIB: +_IF_END192_STDLIB: +_IF_END186_STDLIB: + FPADJ 212 + RET + .CPOOL +NOECHO: + FPADJ -12 + STORE 8 ; OLD + STORE 4 ; NOECHO + STORE 0 ; F + LOAD 0 ; F + LOADC 16 + ADD + LOADI + LOADC 0 + CMP NE + .LCBRANCHZ _IF_ELSE193_STDLIB + LOAD 0 ; F + LOADC 9 + LOADCP FILEERROR + CALL + .LBRANCH _IF_END193_STDLIB +_IF_ELSE193_STDLIB: + LOAD 8 ; OLD + LOAD 0 ; F + LOADC 36 + ADD + LOADI + STOREI + DROP + LOAD 0 ; F + LOADC 36 + ADD + LOAD 4 ; NOECHO + STOREI + DROP +_IF_END193_STDLIB: + FPADJ 12 + RET +RANDOM: + FPADJ -8 + LOADCP RANDOM_STATE ; RANDOM_STATE + LOADI + STORE 4 ; X + LOAD 4 ; X + LOAD 4 ; X + LOADC 13 + LOADCP _SHLM + CALL + XOR + STORE 4 ; X + LOAD 4 ; X + LOAD 4 ; X + LOADC 17 + LOADCP _SHRM + CALL + XOR + STORE 4 ; X + LOAD 4 ; X + LOAD 4 ; X + LOADC 5 + LOADCP _SHLM + CALL + XOR + STORE 4 ; X + LOADCP RANDOM_STATE ; RANDOM_STATE + LOAD 4 ; X + STOREI + DROP + LOAD 4 ; X + LOADC 0 + CMP LT + .LCBRANCHZ _IF_ELSE194_STDLIB + LOAD 4 ; X + LOADCP ABS + CALL + STORE 4 ; X +_IF_ELSE194_STDLIB: +_IF_END194_STDLIB: + LOAD 4 ; X + STORE 0 ; RANDOM + LOAD 0 ; RANDOM + FPADJ 8 + RET +RANDOMIZE: + LOADCP RANDOM_STATE ; RANDOM_STATE + LOADCP GETTICKS + CALL + LOADCP -1342256386 + XOR + STOREI + DROP + RET +CLRSCR: + LOADC 27 + LOADCP OUTPUT + DUP + LOADCP CHECKERROR + CALL + SWAP + OVER + LOADCP FWRITECHAR + CALL + LOADCP _C_S_13_STDLIB + OVER + LOADC 0 + LOADCP FWRITESTRING + CALL + DROP + LOADC 27 + LOADCP OUTPUT + DUP + LOADCP CHECKERROR + CALL + SWAP + OVER + LOADCP FWRITECHAR + CALL + LOADCP _C_S_14_STDLIB + OVER + LOADC 0 + LOADCP FWRITESTRING + CALL + DROP + RET +CLREOL: + LOADC 27 + LOADCP OUTPUT + DUP + LOADCP CHECKERROR + CALL + SWAP + OVER + LOADCP FWRITECHAR + CALL + LOADCP _C_S_15_STDLIB + OVER + LOADC 0 + LOADCP FWRITESTRING + CALL + DROP + RET +CRTINIT: + LOADC 27 + LOADCP OUTPUT + DUP + LOADCP CHECKERROR + CALL + SWAP + OVER + LOADCP FWRITECHAR + CALL + LOADC 99 + OVER + LOADCP FWRITECHAR + CALL + DROP + RET +GOTOXY: + FPADJ -8 + STORE 4 ; Y + STORE 0 ; X + LOADC 27 + LOADCP OUTPUT + DUP + LOADCP CHECKERROR + CALL + SWAP + OVER + LOADCP FWRITECHAR + CALL + LOADC 91 + OVER + LOADCP FWRITECHAR + CALL + LOAD 4 ; Y + OVER + LOADC 0 + LOADCP FWRITEINT + CALL + LOADC 59 + OVER + LOADCP FWRITECHAR + CALL + LOAD 0 ; X + OVER + LOADC 0 + LOADCP FWRITEINT + CALL + LOADC 72 + OVER + LOADCP FWRITECHAR + CALL + DROP + FPADJ 8 + RET +INSLINE: + LOADC 27 + LOADCP OUTPUT + DUP + LOADCP CHECKERROR + CALL + SWAP + OVER + LOADCP FWRITECHAR + CALL + LOADCP _C_S_16_STDLIB + OVER + LOADC 0 + LOADCP FWRITESTRING + CALL + DROP + RET +DELLINE: + LOADC 27 + LOADCP OUTPUT + DUP + LOADCP CHECKERROR + CALL + SWAP + OVER + LOADCP FWRITECHAR + CALL + LOADCP _C_S_17_STDLIB + OVER + LOADC 0 + LOADCP FWRITESTRING + CALL + DROP + RET +GETTERMSIZE: + FPADJ -16 + STORE 4 ; MAXY + STORE 0 ; MAXX + ; X + LOADREG FP + INC 8 + ; Y + LOADREG FP + INC 12 + LOADCP GETCURSORPOS + CALL + LOADCP 9999 + LOADCP 9999 + LOADCP GOTOXY + CALL + LOAD 0 ; MAXX + LOAD 4 ; MAXY + LOADCP GETCURSORPOS + CALL + LOAD 8 ; X + LOAD 12 ; Y + LOADCP GOTOXY + CALL + FPADJ 16 + RET + .CPOOL +TEXTCOLOR: + FPADJ -4 + STORE 0 ; COL + LOADC 27 + LOADCP OUTPUT + DUP + LOADCP CHECKERROR + CALL + SWAP + OVER + LOADCP FWRITECHAR + CALL + LOADCP _C_S_18_STDLIB + OVER + LOADC 0 + LOADCP FWRITESTRING + CALL + LOAD 0 ; COL + OVER + LOADC 0 + LOADCP FWRITEINT + CALL + LOADC 109 + OVER + LOADCP FWRITECHAR + CALL + DROP + FPADJ 4 + RET +TEXTBACKGROUND: + FPADJ -4 + STORE 0 ; BGCOL + LOADC 27 + LOADCP OUTPUT + DUP + LOADCP CHECKERROR + CALL + SWAP + OVER + LOADCP FWRITECHAR + CALL + LOADCP _C_S_19_STDLIB + OVER + LOADC 0 + LOADCP FWRITESTRING + CALL + LOAD 0 ; BGCOL + OVER + LOADC 0 + LOADCP FWRITEINT + CALL + LOADC 109 + OVER + LOADCP FWRITECHAR + CALL + DROP + FPADJ 4 + RET +TEXTDEFAULT: + LOADC 27 + LOADCP OUTPUT + DUP + LOADCP CHECKERROR + CALL + SWAP + OVER + LOADCP FWRITECHAR + CALL + LOADCP _C_S_20_STDLIB + OVER + LOADC 0 + LOADCP FWRITESTRING + CALL + DROP + RET +PEXEC: + FPADJ -216 + STORE 84 ; ERROR + STORE 80 ; ARGCOUNT + STORE 76 ; ARGS + ; PRGFILE + LOADREG FP + SWAP + LOADC 68 + LOADCP _INITSTRINGFROM + CALL + LOADC 32 + ; FNAME + LOADREG FP + LOADC 92 + ADD + LOADCP _INITSTRINGF + CALL + ; DIRSLOT + LOADREG FP + LOADC 132 + ADD + LOADC 64 + LOADCP _CLEARMEM + CALL + LOAD 80 ; ARGCOUNT + LOADC 7 + CMP GE + LOAD 80 ; ARGCOUNT + LOADC 0 + CMP LT + OR + .LCBRANCHZ _IF_ELSE195_STDLIB + LOAD 84 ; ERROR + LOADC 9 + STOREI + DROP + .LBRANCH _IF_END195_STDLIB +_IF_ELSE195_STDLIB: + ; PRGFILE + LOADREG FP + ; VOLID + LOADREG FP + LOADC 88 + ADD + ; FNAME + LOADREG FP + LOADC 92 + ADD + ; SLOTNO + LOADREG FP + LOADC 196 + ADD + ; DIRSLOT + LOADREG FP + LOADC 132 + ADD + LOAD 84 ; ERROR + LOADCP OPENVOLPATH + CALL + LOAD 84 ; ERROR + LOADI + LOADC 0 + CMP EQ + .LCBRANCHZ _IF_ELSE196_STDLIB + LOADCP VOLUMETABLE ; VOLUMETABLE + LOAD 88 ; VOLID + DEC 1 + DUP + LOADC 32 + LOADCP _BOUNDSCHECK + CALL + LOADC 96 + LOADCP _MULU + CALL + ADD + LOADREG FP + DEC 4 + SWAP + STOREI + DROP + LOADREG FP + DEC 4 + LOADI + LOADC 64 + ADD + LOADI + STORE 212 ; DEVID + LOAD 196 ; SLOTNO + LOADREG FP + DEC 4 + LOADI + LOADC 52 + ADD + LOADI + FPADJ -4 + LOADCP _MUL + CALL + FPADJ 4 + LOADC 512 + FPADJ -4 + LOADCP _DIV + CALL + FPADJ 4 + STORE 204 ; STARTBLOCK + LOAD 88 ; VOLID + LOAD 204 ; STARTBLOCK + LOADCP GETPHYSBLOCKNO + CALL + STORE 208 ; PHYSBLOCK + LOAD 88 ; VOLID + LOADCP CLOSEVOLUMEID + CALL + LOADCP PARGS ; PARGS + LOADC 0 + DUP + LOADC 8 + LOADCP _BOUNDSCHECK + CALL + LOADC 88 + LOADCP _MULU + CALL + ADD + ; PRGFILE + LOADREG FP + LOADC 80 + LOADCP _INITSTRINGFROM + CALL + LOADC 1 + STORE 200 ; I + LOAD 80 ; ARGCOUNT +_FOR_START18_STDLIB: + LOAD 200 ; I + OVER + CMP GT + .LCBRANCH _FOR_END18_STDLIB + LOADCP PARGS ; PARGS + LOAD 200 ; I + DUP + LOADC 8 + LOADCP _BOUNDSCHECK + CALL + LOADC 88 + LOADCP _MULU + CALL + ADD + LOAD 76 ; ARGS + LOAD 200 ; I + LOADC 1 + SUB + DUP + LOADC 8 + LOADCP _BOUNDSCHECK + CALL + LOADC 88 + LOADCP _MULU + CALL + ADD + LOADC 80 + LOADCP _INITSTRINGFROM + CALL + LOAD 200 ; I + INC 1 + STORE 200 ; I + .LBRANCH _FOR_START18_STDLIB + .CPOOL +_FOR_END18_STDLIB: + DROP + LOAD 80 ; ARGCOUNT + LOADC 1 + ADD + STORE 200 ; I + LOADC 7 +_FOR_START19_STDLIB: + LOAD 200 ; I + OVER + CMP GT + .LCBRANCH _FOR_END19_STDLIB + LOADCP PARGS ; PARGS + LOAD 200 ; I + DUP + LOADC 8 + LOADCP _BOUNDSCHECK + CALL + LOADC 88 + LOADCP _MULU + CALL + ADD + LOADCP _C_S_3_STDLIB + LOADC 80 + LOADCP _INITSTRINGFROM + CALL + LOAD 200 ; I + INC 1 + STORE 200 ; I + .LBRANCH _FOR_START19_STDLIB +_FOR_END19_STDLIB: + DROP + LOADCP PARGCOUNT ; PARGCOUNT + LOAD 80 ; ARGCOUNT + STOREI + DROP + LOAD 212 ; DEVID + LOAD 208 ; PHYSBLOCK + LOAD 176 ; DIRSLOT + LOADCP CORELOAD + CALL +_IF_ELSE196_STDLIB: +_IF_END196_STDLIB: +_IF_END195_STDLIB: + FPADJ 216 + RET +PEXEC2: + LOADREG FP + LOADC 872 + SUB + STOREREG FP + STORE 164 ; ERROR + ; ARG1 + LOADREG FP + LOADC 76 + ADD + SWAP + LOADC 80 + LOADCP _INITSTRINGFROM + CALL + ; PRGFILE + LOADREG FP + SWAP + LOADC 68 + LOADCP _INITSTRINGFROM + CALL + ; ARGS + LOADREG FP + LOADC 168 + ADD + LOADC 704 + LOADCP _CLEARMEM + CALL + ; ARGS + LOADREG FP + LOADC 168 + ADD + LOADC 0 + DUP + LOADC 8 + LOADCP _BOUNDSCHECK + CALL + LOADC 88 + LOADCP _MULU + CALL + ADD + ; ARG1 + LOADREG FP + LOADC 76 + ADD + LOADC 80 + LOADCP _INITSTRINGFROM + CALL + ; PRGFILE + LOADREG FP + ; ARGS + LOADREG FP + LOADC 168 + ADD + LOADC 1 + LOAD 164 ; ERROR + LOADCP PEXEC + CALL + LOADREG FP + LOADC 872 + ADD + STOREREG FP + RET +PEXEC3: + LOADREG FP + LOADC 960 + SUB + STOREREG FP + STORE 252 ; ERROR + ; ARG2 + LOADREG FP + LOADC 164 + ADD + SWAP + LOADC 80 + LOADCP _INITSTRINGFROM + CALL + ; ARG1 + LOADREG FP + LOADC 76 + ADD + SWAP + LOADC 80 + LOADCP _INITSTRINGFROM + CALL + ; PRGFILE + LOADREG FP + SWAP + LOADC 68 + LOADCP _INITSTRINGFROM + CALL + ; ARGS + LOADREG FP + LOADC 256 + ADD + LOADC 704 + LOADCP _CLEARMEM + CALL + ; ARGS + LOADREG FP + LOADC 256 + ADD + LOADC 0 + DUP + LOADC 8 + LOADCP _BOUNDSCHECK + CALL + LOADC 88 + LOADCP _MULU + CALL + ADD + ; ARG1 + LOADREG FP + LOADC 76 + ADD + LOADC 80 + LOADCP _INITSTRINGFROM + CALL + ; ARGS + LOADREG FP + LOADC 256 + ADD + LOADC 1 + DUP + LOADC 8 + LOADCP _BOUNDSCHECK + CALL + LOADC 88 + LOADCP _MULU + CALL + ADD + ; ARG2 + LOADREG FP + LOADC 164 + ADD + LOADC 80 + LOADCP _INITSTRINGFROM + CALL + ; PRGFILE + LOADREG FP + ; ARGS + LOADREG FP + LOADC 256 + ADD + LOADC 2 + LOAD 252 ; ERROR + LOADCP PEXEC + CALL + LOADREG FP + LOADC 960 + ADD + STOREREG FP + RET +PARAMSTR: + FPADJ -8 + STORE 4 ; PARAMSTR + STORE 0 ; I + LOAD 0 ; I + LOADC 0 + CMP LT + LOAD 0 ; I + LOADC 7 + CMP GT + OR + .LCBRANCHZ _IF_ELSE197_STDLIB + LOAD 4 ; PARAMSTR + LOADCP _C_S_3_STDLIB + LOADCP _COPYSTRING + CALL + .LBRANCH _IF_END197_STDLIB +_IF_ELSE197_STDLIB: + LOAD 4 ; PARAMSTR + LOADCP PARGS ; PARGS + LOAD 0 ; I + DUP + LOADC 8 + LOADCP _BOUNDSCHECK + CALL + LOADC 88 + LOADCP _MULU + CALL + ADD + LOADCP _COPYSTRING + CALL +_IF_END197_STDLIB: + LOAD 4 ; PARAMSTR + FPADJ 8 + RET +PARAMCOUNT: + FPADJ -4 + LOADCP PARGCOUNT ; PARGCOUNT + LOADI + STORE 0 ; PARAMCOUNT + LOAD 0 ; PARAMCOUNT + FPADJ 4 + RET +SETSHELLCMD: + FPADJ -52 + STORE 48 ; ARG + ; CMD + LOADREG FP + SWAP + LOADC 40 + LOADCP _INITSTRINGFROM + CALL + LOADCP SHELLCMD ; SHELLCMD + ; CMD + LOADREG FP + LOADCP _COPYSTRING + CALL + LOADCP SHELLARG ; SHELLARG + LOAD 48 ; ARG + STOREI + DROP + FPADJ 52 + RET + .CPOOL +DELAY: + FPADJ -8 + STORE 0 ; MS + LOAD 0 ; MS + STORE 4 ; COUNT +_WHILE_START14_STDLIB: + LOAD 4 ; COUNT + LOADC 0 + CMP GT + .LCBRANCHZ _WHILE_END14_STDLIB + LOADCP WAIT1MSEC + CALL + LOAD 4 ; COUNT + LOADC 1 + SUB + STORE 4 ; COUNT + .LBRANCH _WHILE_START14_STDLIB +_WHILE_END14_STDLIB: + FPADJ 8 + RET + .CPOOL +INPUT: .BLOCK 18 +OUTPUT: .BLOCK 18 +DEFAULTVOLUMEID: .WORD 0 +VOLUMETABLE: .BLOCK 768 +VOLUMECOUNT: .WORD 0 +DEVICESINITIALIZED: .WORD 0 +RANDOM_STATE: .WORD 0 +_C_S_0_STDLIB: + .WORD 1,0 + .BYTE "0" +_C_S_1_STDLIB: + .WORD 1,0 + .BYTE ":" +_C_S_2_STDLIB: + .WORD 1,0 + .BYTE "-" +_C_S_3_STDLIB: + .WORD 0,0 +_C_S_4_STDLIB: + .WORD 10,0 + .BYTE "8463847412" +_C_S_5_STDLIB: + .WORD 1,0 + .BYTE " " +_C_S_6_STDLIB: + .WORD 1,0 + .BYTE "E" +_C_S_7_STDLIB: + .WORD 2,0 + .BYTE "0." +_C_S_8_STDLIB: + .WORD 30,0 + .BYTE "Error reading partition block " +_C_S_9_STDLIB: + .WORD 18,0 + .BYTE "Invalid error code" +_C_S_10_STDLIB: + .WORD 4,0 + .BYTE "%CON" +_C_S_11_STDLIB: + .WORD 4,0 + .BYTE "%KBD" +_C_S_12_STDLIB: + .WORD 4,0 + .BYTE "%RAW" +_C_S_13_STDLIB: + .WORD 3,0 + .BYTE "[2J" +_C_S_14_STDLIB: + .WORD 2,0 + .BYTE "[H" +_C_S_15_STDLIB: + .WORD 2,0 + .BYTE "[K" +_C_S_16_STDLIB: + .WORD 2,0 + .BYTE "[L" +_C_S_17_STDLIB: + .WORD 2,0 + .BYTE "[M" +_C_S_18_STDLIB: + .WORD 6,0 + .BYTE "[38;5;" +_C_S_19_STDLIB: + .WORD 6,0 + .BYTE "[48;5;" +_C_S_20_STDLIB: + .WORD 3,0 + .BYTE "[0m" +IOERRORDESC: +_C_A_1_STDLIB: + + .WORD 8,20 + .BYTE "No error" + .BLOCK 3 + + .WORD 14,20 + .BYTE "File not found" + .BLOCK 1 + + .WORD 16,20 + .BYTE "Volume not found" + .BLOCK 1 + + .WORD 12,20 + .BYTE "Path invalid" + .BLOCK 2 + + .WORD 19,20 + .BYTE "File already exists" + + .WORD 11,20 + .BYTE "File closed" + .BLOCK 2 + + .WORD 12,20 + .BYTE "Seek invalid" + .BLOCK 2 + + .WORD 8,20 + .BYTE "No space" + .BLOCK 3 + + .WORD 16,20 + .BYTE "File is readonly" + .BLOCK 1 + + .WORD 17,20 + .BYTE "Invalid operation" + + .WORD 14,20 + .BYTE "Invalid format" + .BLOCK 1 + + .WORD 19,20 + .BYTE "Interrupted by user" + +MATHERROR: +_C_A_2_STDLIB: + + .WORD 37,38 + .BYTE "Invalid argument to sqrt/ln/tan/cotan" + +PEXECERROR: +_C_A_3_STDLIB: + + .WORD 27,28 + .BYTE "Invalid arguments for PExec" + +DATETIMEMTAB: +_C_A_4_STDLIB: + + .WORD 31,28,31,30,31,30,31,31 + .WORD 30,31,30,31,31,29,31,30 + .WORD 31,30,31,31,30,31,30,31 +_C_A_5_STDLIB: + + .WORD 32,9,13,10 +_C_A_6_STDLIB: + + .WORD 10,13,32,9 +_C_A_7_STDLIB: + + .WORD 43,45,46,69,101 +_C_A_8_STDLIB: + + .WORD 35,37 diff --git a/rtl/arty-a7/Arty-A7-35-Master.xdc b/rtl/arty-a7/Arty-A7-35-Master.xdc new file mode 100644 index 0000000..c618478 --- /dev/null +++ b/rtl/arty-a7/Arty-A7-35-Master.xdc @@ -0,0 +1,218 @@ +## This file is a general .xdc for the Arty A7-35 Rev. D +## To use it in a project: +## - uncomment the lines corresponding to used pins +## - rename the used ports (in each line, after get_ports) according to the top level signal names in the project + +## Clock signal +set_property -dict {PACKAGE_PIN E3 IOSTANDARD LVCMOS33} [get_ports clk] +create_clock -period 10.000 -name sys_clk_pin -waveform {0.000 5.000} -add [get_ports clk] + +## Switches +set_property -dict {PACKAGE_PIN A8 IOSTANDARD LVCMOS33} [get_ports sw0] +set_property -dict {PACKAGE_PIN C11 IOSTANDARD LVCMOS33} [get_ports sw1] +#set_property -dict { PACKAGE_PIN C10 IOSTANDARD LVCMOS33 } [get_ports { sw[2] }]; #IO_L13N_T2_MRCC_16 Sch=sw[2] +#set_property -dict { PACKAGE_PIN A10 IOSTANDARD LVCMOS33 } [get_ports { sw[3] }]; #IO_L14P_T2_SRCC_16 Sch=sw[3] + +## RGB LEDs +#set_property -dict { PACKAGE_PIN E1 IOSTANDARD LVCMOS33 } [get_ports { led0_b }]; #IO_L18N_T2_35 Sch=led0_b +#set_property -dict { PACKAGE_PIN F6 IOSTANDARD LVCMOS33 } [get_ports { led0_g }]; #IO_L19N_T3_VREF_35 Sch=led0_g +#set_property -dict { PACKAGE_PIN G6 IOSTANDARD LVCMOS33 } [get_ports { led0_r }]; #IO_L19P_T3_35 Sch=led0_r +#set_property -dict { PACKAGE_PIN G4 IOSTANDARD LVCMOS33 } [get_ports { led1_b }]; #IO_L20P_T3_35 Sch=led1_b +#set_property -dict { PACKAGE_PIN J4 IOSTANDARD LVCMOS33 } [get_ports { led1_g }]; #IO_L21P_T3_DQS_35 Sch=led1_g +#set_property -dict { PACKAGE_PIN G3 IOSTANDARD LVCMOS33 } [get_ports { led1_r }]; #IO_L20N_T3_35 Sch=led1_r +#set_property -dict { PACKAGE_PIN H4 IOSTANDARD LVCMOS33 } [get_ports { led2_b }]; #IO_L21N_T3_DQS_35 Sch=led2_b +#set_property -dict { PACKAGE_PIN J2 IOSTANDARD LVCMOS33 } [get_ports { led2_g }]; #IO_L22N_T3_35 Sch=led2_g +#set_property -dict { PACKAGE_PIN J3 IOSTANDARD LVCMOS33 } [get_ports { led2_r }]; #IO_L22P_T3_35 Sch=led2_r +#set_property -dict { PACKAGE_PIN K2 IOSTANDARD LVCMOS33 } [get_ports { led3_b }]; #IO_L23P_T3_35 Sch=led3_b +#set_property -dict { PACKAGE_PIN H6 IOSTANDARD LVCMOS33 } [get_ports { led3_g }]; #IO_L24P_T3_35 Sch=led3_g +#set_property -dict { PACKAGE_PIN K1 IOSTANDARD LVCMOS33 } [get_ports { led3_r }]; #IO_L23N_T3_35 Sch=led3_r + +## LEDs +set_property -dict {PACKAGE_PIN H5 IOSTANDARD LVCMOS33} [get_ports led0] +set_property -dict {PACKAGE_PIN J5 IOSTANDARD LVCMOS33} [get_ports led1] +set_property -dict {PACKAGE_PIN T9 IOSTANDARD LVCMOS33} [get_ports led2] +set_property -dict {PACKAGE_PIN T10 IOSTANDARD LVCMOS33} [get_ports led3] + +## Buttons +set_property -dict {PACKAGE_PIN D9 IOSTANDARD LVCMOS33} [get_ports btn0] +#set_property -dict { PACKAGE_PIN C9 IOSTANDARD LVCMOS33 } [get_ports { btn1 }]; #IO_L11P_T1_SRCC_16 Sch=btn[1] +#set_property -dict { PACKAGE_PIN B9 IOSTANDARD LVCMOS33 } [get_ports { btn[2] }]; #IO_L11N_T1_SRCC_16 Sch=btn[2] +#set_property -dict { PACKAGE_PIN B8 IOSTANDARD LVCMOS33 } [get_ports { btn[3] }]; #IO_L12P_T1_MRCC_16 Sch=btn[3] + +## Pmod Header JA +set_property -dict {PACKAGE_PIN G13 IOSTANDARD LVCMOS33} [get_ports sd_cs_n] +set_property -dict {PACKAGE_PIN B11 IOSTANDARD LVCMOS33} [get_ports sd_mosi] +set_property -dict {PACKAGE_PIN A11 IOSTANDARD LVCMOS33} [get_ports sd_miso] +set_property -dict {PACKAGE_PIN D12 IOSTANDARD LVCMOS33} [get_ports sd_sck] +#set_property -dict { PACKAGE_PIN D13 IOSTANDARD LVCMOS33 } [get_ports { sd_dat1 }]; #IO_L6N_T0_VREF_15 Sch=ja[7] +#set_property -dict { PACKAGE_PIN B18 IOSTANDARD LVCMOS33 } [get_ports { sd_dat2 }]; #IO_L10P_T1_AD11P_15 Sch=ja[8] +set_property -dict {PACKAGE_PIN A18 IOSTANDARD LVCMOS33} [get_ports sd_cd] +#set_property -dict { PACKAGE_PIN K16 IOSTANDARD LVCMOS33 } [get_ports { sd_nc }]; #IO_25_15 Sch=ja[10] + +###Pmod Header JB +set_property -dict {PACKAGE_PIN E15 IOSTANDARD LVCMOS33} [get_ports {VGA_R[0]}] +set_property -dict {PACKAGE_PIN E16 IOSTANDARD LVCMOS33} [get_ports {VGA_R[1]}] +set_property -dict {PACKAGE_PIN D15 IOSTANDARD LVCMOS33} [get_ports {VGA_R[2]}] +set_property -dict {PACKAGE_PIN C15 IOSTANDARD LVCMOS33} [get_ports {VGA_R[3]}] +set_property -dict {PACKAGE_PIN J17 IOSTANDARD LVCMOS33} [get_ports {VGA_B[0]}] +set_property -dict {PACKAGE_PIN J18 IOSTANDARD LVCMOS33} [get_ports {VGA_B[1]}] +set_property -dict {PACKAGE_PIN K15 IOSTANDARD LVCMOS33} [get_ports {VGA_B[2]}] +set_property -dict {PACKAGE_PIN J15 IOSTANDARD LVCMOS33} [get_ports {VGA_B[3]}] + +###Pmod Header JC +set_property -dict {PACKAGE_PIN U12 IOSTANDARD LVCMOS33} [get_ports {VGA_G[0]}] +set_property -dict {PACKAGE_PIN V12 IOSTANDARD LVCMOS33} [get_ports {VGA_G[1]}] +set_property -dict {PACKAGE_PIN V10 IOSTANDARD LVCMOS33} [get_ports {VGA_G[2]}] +set_property -dict {PACKAGE_PIN V11 IOSTANDARD LVCMOS33} [get_ports {VGA_G[3]}] +set_property -dict {PACKAGE_PIN U14 IOSTANDARD LVCMOS33} [get_ports VGA_HS_O] +set_property -dict {PACKAGE_PIN V14 IOSTANDARD LVCMOS33} [get_ports VGA_VS_O] +#set_property -dict { PACKAGE_PIN T13 IOSTANDARD LVCMOS33 } [get_ports { jc[6] }]; #IO_L23P_T3_A03_D19_14 Sch=jc_p[4] +#set_property -dict { PACKAGE_PIN U13 IOSTANDARD LVCMOS33 } [get_ports { jc[7] }]; #IO_L23N_T3_A02_D18_14 Sch=jc_n[4] + +## Pmod Header JD +#set_property -dict { PACKAGE_PIN D4 IOSTANDARD LVCMOS33 } [get_ports { jd[0] }]; #IO_L11N_T1_SRCC_35 Sch=jd[1] +#set_property -dict { PACKAGE_PIN D3 IOSTANDARD LVCMOS33 } [get_ports { jd[1] }]; #IO_L12N_T1_MRCC_35 Sch=jd[2] +#set_property -dict { PACKAGE_PIN F4 IOSTANDARD LVCMOS33 } [get_ports { jd[2] }]; #IO_L13P_T2_MRCC_35 Sch=jd[3] +#set_property -dict { PACKAGE_PIN F3 IOSTANDARD LVCMOS33 } [get_ports { jd[3] }]; #IO_L13N_T2_MRCC_35 Sch=jd[4] +#set_property -dict { PACKAGE_PIN E2 IOSTANDARD LVCMOS33 } [get_ports { jd[4] }]; #IO_L14P_T2_SRCC_35 Sch=jd[7] +#set_property -dict { PACKAGE_PIN D2 IOSTANDARD LVCMOS33 } [get_ports { jd[5] }]; #IO_L14N_T2_SRCC_35 Sch=jd[8] +#set_property -dict { PACKAGE_PIN H2 IOSTANDARD LVCMOS33 } [get_ports { jd[6] }]; #IO_L15P_T2_DQS_35 Sch=jd[9] +#set_property -dict { PACKAGE_PIN G2 IOSTANDARD LVCMOS33 } [get_ports { jd[7] }]; #IO_L15N_T2_DQS_35 Sch=jd[10] + +## USB-UART Interface +set_property -dict {PACKAGE_PIN D10 IOSTANDARD LVCMOS33} [get_ports uart_rxd_out] +set_property -dict {PACKAGE_PIN A9 IOSTANDARD LVCMOS33} [get_ports uart_txd_in] + +## ChipKit Outer Digital Header +#set_property -dict { PACKAGE_PIN V15 IOSTANDARD LVCMOS33 } [get_ports { ck_io0 }]; #IO_L16P_T2_CSI_B_14 Sch=ck_io[0] +#set_property -dict { PACKAGE_PIN U16 IOSTANDARD LVCMOS33 } [get_ports { ck_io1 }]; #IO_L18P_T2_A12_D28_14 Sch=ck_io[1] +#set_property -dict { PACKAGE_PIN P14 IOSTANDARD LVCMOS33 } [get_ports { ck_io2 }]; #IO_L8N_T1_D12_14 Sch=ck_io[2] +#set_property -dict { PACKAGE_PIN T11 IOSTANDARD LVCMOS33 } [get_ports { ck_io3 }]; #IO_L19P_T3_A10_D26_14 Sch=ck_io[3] +#set_property -dict { PACKAGE_PIN R12 IOSTANDARD LVCMOS33 } [get_ports { ck_io4 }]; #IO_L5P_T0_D06_14 Sch=ck_io[4] +#set_property -dict { PACKAGE_PIN T14 IOSTANDARD LVCMOS33 } [get_ports { ck_io5 }]; #IO_L14P_T2_SRCC_14 Sch=ck_io[5] +#set_property -dict { PACKAGE_PIN T15 IOSTANDARD LVCMOS33 } [get_ports { ck_io6 }]; #IO_L14N_T2_SRCC_14 Sch=ck_io[6] +#set_property -dict { PACKAGE_PIN T16 IOSTANDARD LVCMOS33 } [get_ports { ck_io7 }]; #IO_L15N_T2_DQS_DOUT_CSO_B_14 Sch=ck_io[7] +#set_property -dict { PACKAGE_PIN N15 IOSTANDARD LVCMOS33 } [get_ports { ck_io8 }]; #IO_L11P_T1_SRCC_14 Sch=ck_io[8] +#set_property -dict { PACKAGE_PIN M16 IOSTANDARD LVCMOS33 } [get_ports { ck_io9 }]; #IO_L10P_T1_D14_14 Sch=ck_io[9] +#set_property -dict { PACKAGE_PIN V17 IOSTANDARD LVCMOS33 } [get_ports { ck_io10 }]; #IO_L18N_T2_A11_D27_14 Sch=ck_io[10] +#set_property -dict { PACKAGE_PIN U18 IOSTANDARD LVCMOS33 } [get_ports { ck_io11 }]; #IO_L17N_T2_A13_D29_14 Sch=ck_io[11] +#set_property -dict { PACKAGE_PIN R17 IOSTANDARD LVCMOS33 } [get_ports { ck_io12 }]; #IO_L12N_T1_MRCC_14 Sch=ck_io[12] +#set_property -dict { PACKAGE_PIN P17 IOSTANDARD LVCMOS33 } [get_ports { ck_io13 }]; #IO_L12P_T1_MRCC_14 Sch=ck_io[13] + +## ChipKit Inner Digital Header +#set_property -dict { PACKAGE_PIN U11 IOSTANDARD LVCMOS33 } [get_ports { ck_io26 }]; #IO_L19N_T3_A09_D25_VREF_14 Sch=ck_io[26] +#set_property -dict { PACKAGE_PIN V16 IOSTANDARD LVCMOS33 } [get_ports { ck_io27 }]; #IO_L16N_T2_A15_D31_14 Sch=ck_io[27] +#set_property -dict { PACKAGE_PIN M13 IOSTANDARD LVCMOS33 } [get_ports { ck_io28 }]; #IO_L6N_T0_D08_VREF_14 Sch=ck_io[28] +#set_property -dict { PACKAGE_PIN R10 IOSTANDARD LVCMOS33 } [get_ports { ck_io29 }]; #IO_25_14 Sch=ck_io[29] +#set_property -dict { PACKAGE_PIN R11 IOSTANDARD LVCMOS33 } [get_ports { ck_io30 }]; #IO_0_14 Sch=ck_io[30] +#set_property -dict { PACKAGE_PIN R13 IOSTANDARD LVCMOS33 } [get_ports { ck_io31 }]; #IO_L5N_T0_D07_14 Sch=ck_io[31] +#set_property -dict { PACKAGE_PIN R15 IOSTANDARD LVCMOS33 } [get_ports { ck_io32 }]; #IO_L13N_T2_MRCC_14 Sch=ck_io[32] +#set_property -dict { PACKAGE_PIN P15 IOSTANDARD LVCMOS33 } [get_ports { ck_io33 }]; #IO_L13P_T2_MRCC_14 Sch=ck_io[33] +#set_property -dict { PACKAGE_PIN R16 IOSTANDARD LVCMOS33 } [get_ports { ck_io34 }]; #IO_L15P_T2_DQS_RDWR_B_14 Sch=ck_io[34] +#set_property -dict { PACKAGE_PIN N16 IOSTANDARD LVCMOS33 } [get_ports { ck_io35 }]; #IO_L11N_T1_SRCC_14 Sch=ck_io[35] +#set_property -dict { PACKAGE_PIN N14 IOSTANDARD LVCMOS33 } [get_ports { ck_io36 }]; #IO_L8P_T1_D11_14 Sch=ck_io[36] +#set_property -dict { PACKAGE_PIN U17 IOSTANDARD LVCMOS33 } [get_ports { ck_io37 }]; #IO_L17P_T2_A14_D30_14 Sch=ck_io[37] +#set_property -dict { PACKAGE_PIN T18 IOSTANDARD LVCMOS33 } [get_ports { ck_io38 }]; #IO_L7N_T1_D10_14 Sch=ck_io[38] +#set_property -dict { PACKAGE_PIN R18 IOSTANDARD LVCMOS33 } [get_ports { ck_io39 }]; #IO_L7P_T1_D09_14 Sch=ck_io[39] +#set_property -dict { PACKAGE_PIN P18 IOSTANDARD LVCMOS33 } [get_ports { ck_io40 }]; #IO_L9N_T1_DQS_D13_14 Sch=ck_io[40] +#set_property -dict { PACKAGE_PIN N17 IOSTANDARD LVCMOS33 } [get_ports { ck_io41 }]; #IO_L9P_T1_DQS_14 Sch=ck_io[41] + +## ChipKit Outer Analog Header - as Single-Ended Analog Inputs +## NOTE: These ports can be used as single-ended analog inputs with voltages from 0-3.3V (ChipKit analog pins A0-A5) or as digital I/O. +## WARNING: Do not use both sets of constraints at the same time! +## NOTE: The following constraints should be used with the XADC IP core when using these ports as analog inputs. +#set_property -dict { PACKAGE_PIN C5 IOSTANDARD LVCMOS33 } [get_ports { vaux4_n }]; #IO_L1N_T0_AD4N_35 Sch=ck_an_n[0] ChipKit pin=A0 +#set_property -dict { PACKAGE_PIN C6 IOSTANDARD LVCMOS33 } [get_ports { vaux4_p }]; #IO_L1P_T0_AD4P_35 Sch=ck_an_p[0] ChipKit pin=A0 +#set_property -dict { PACKAGE_PIN A5 IOSTANDARD LVCMOS33 } [get_ports { vaux5_n }]; #IO_L3N_T0_DQS_AD5N_35 Sch=ck_an_n[1] ChipKit pin=A1 +#set_property -dict { PACKAGE_PIN A6 IOSTANDARD LVCMOS33 } [get_ports { vaux5_p }]; #IO_L3P_T0_DQS_AD5P_35 Sch=ck_an_p[1] ChipKit pin=A1 +#set_property -dict { PACKAGE_PIN B4 IOSTANDARD LVCMOS33 } [get_ports { vaux6_n }]; #IO_L7N_T1_AD6N_35 Sch=ck_an_n[2] ChipKit pin=A2 +#set_property -dict { PACKAGE_PIN C4 IOSTANDARD LVCMOS33 } [get_ports { vaux6_p }]; #IO_L7P_T1_AD6P_35 Sch=ck_an_p[2] ChipKit pin=A2 +#set_property -dict { PACKAGE_PIN A1 IOSTANDARD LVCMOS33 } [get_ports { vaux7_n }]; #IO_L9N_T1_DQS_AD7N_35 Sch=ck_an_n[3] ChipKit pin=A3 +#set_property -dict { PACKAGE_PIN B1 IOSTANDARD LVCMOS33 } [get_ports { vaux7_p }]; #IO_L9P_T1_DQS_AD7P_35 Sch=ck_an_p[3] ChipKit pin=A3 +#set_property -dict { PACKAGE_PIN B2 IOSTANDARD LVCMOS33 } [get_ports { vaux15_n }]; #IO_L10N_T1_AD15N_35 Sch=ck_an_n[4] ChipKit pin=A4 +#set_property -dict { PACKAGE_PIN B3 IOSTANDARD LVCMOS33 } [get_ports { vaux15_p }]; #IO_L10P_T1_AD15P_35 Sch=ck_an_p[4] ChipKit pin=A4 +#set_property -dict { PACKAGE_PIN C14 IOSTANDARD LVCMOS33 } [get_ports { vaux0_n }]; #IO_L1N_T0_AD0N_15 Sch=ck_an_n[5] ChipKit pin=A5 +#set_property -dict { PACKAGE_PIN D14 IOSTANDARD LVCMOS33 } [get_ports { vaux0_p }]; #IO_L1P_T0_AD0P_15 Sch=ck_an_p[5] ChipKit pin=A5 +## ChipKit Outer Analog Header - as Digital I/O +## NOTE: the following constraints should be used when using these ports as digital I/O. +#set_property -dict { PACKAGE_PIN F5 IOSTANDARD LVCMOS33 } [get_ports { ck_a0 }]; #IO_0_35 Sch=ck_a[0] ChipKit pin=A0 +#set_property -dict { PACKAGE_PIN D8 IOSTANDARD LVCMOS33 } [get_ports { ck_a1 }]; #IO_L4P_T0_35 Sch=ck_a[1] ChipKit pin=A1 +#set_property -dict { PACKAGE_PIN C7 IOSTANDARD LVCMOS33 } [get_ports { ck_a2 }]; #IO_L4N_T0_35 Sch=ck_a[2] ChipKit pin=A2 +#set_property -dict { PACKAGE_PIN E7 IOSTANDARD LVCMOS33 } [get_ports { ck_a3 }]; #IO_L6P_T0_35 Sch=ck_a[3] ChipKit pin=A3 +#set_property -dict { PACKAGE_PIN D7 IOSTANDARD LVCMOS33 } [get_ports { ck_a4 }]; #IO_L6N_T0_VREF_35 Sch=ck_a[4] ChipKit pin=A4 +#set_property -dict { PACKAGE_PIN D5 IOSTANDARD LVCMOS33 } [get_ports { ck_a5 }]; #IO_L11P_T1_SRCC_35 Sch=ck_a[5] ChipKit pin=A5 + +## ChipKit Inner Analog Header - as Differential Analog Inputs +## NOTE: These ports can be used as differential analog inputs with voltages from 0-1.0V (ChipKit Analog pins A6-A11) or as digital I/O. +## WARNING: Do not use both sets of constraints at the same time! +## NOTE: The following constraints should be used with the XADC core when using these ports as analog inputs. +#set_property -dict { PACKAGE_PIN B7 IOSTANDARD LVCMOS33 } [get_ports { vaux12_p }]; #IO_L2P_T0_AD12P_35 Sch=ad_p[12] ChipKit pin=A6 +#set_property -dict { PACKAGE_PIN B6 IOSTANDARD LVCMOS33 } [get_ports { vaux12_n }]; #IO_L2N_T0_AD12N_35 Sch=ad_n[12] ChipKit pin=A7 +#set_property -dict { PACKAGE_PIN E6 IOSTANDARD LVCMOS33 } [get_ports { vaux13_p }]; #IO_L5P_T0_AD13P_35 Sch=ad_p[13] ChipKit pin=A8 +#set_property -dict { PACKAGE_PIN E5 IOSTANDARD LVCMOS33 } [get_ports { vaux13_n }]; #IO_L5N_T0_AD13N_35 Sch=ad_n[13] ChipKit pin=A9 +#set_property -dict { PACKAGE_PIN A4 IOSTANDARD LVCMOS33 } [get_ports { vaux14_p }]; #IO_L8P_T1_AD14P_35 Sch=ad_p[14] ChipKit pin=A10 +#set_property -dict { PACKAGE_PIN A3 IOSTANDARD LVCMOS33 } [get_ports { vaux14_n }]; #IO_L8N_T1_AD14N_35 Sch=ad_n[14] ChipKit pin=A11 +## ChipKit Inner Analog Header - as Digital I/O +## NOTE: the following constraints should be used when using the inner analog header ports as digital I/O. +#set_property -dict { PACKAGE_PIN B7 IOSTANDARD LVCMOS33 } [get_ports { ck_io20 }]; #IO_L2P_T0_AD12P_35 Sch=ad_p[12] ChipKit pin=A6 +#set_property -dict { PACKAGE_PIN B6 IOSTANDARD LVCMOS33 } [get_ports { ck_io21 }]; #IO_L2N_T0_AD12N_35 Sch=ad_n[12] ChipKit pin=A7 +#set_property -dict { PACKAGE_PIN E6 IOSTANDARD LVCMOS33 } [get_ports { ck_io22 }]; #IO_L5P_T0_AD13P_35 Sch=ad_p[13] ChipKit pin=A8 +#set_property -dict { PACKAGE_PIN E5 IOSTANDARD LVCMOS33 } [get_ports { ck_io23 }]; #IO_L5N_T0_AD13N_35 Sch=ad_n[13] ChipKit pin=A9 +#set_property -dict { PACKAGE_PIN A4 IOSTANDARD LVCMOS33 } [get_ports { ck_io24 }]; #IO_L8P_T1_AD14P_35 Sch=ad_p[14] ChipKit pin=A10 +#set_property -dict { PACKAGE_PIN A3 IOSTANDARD LVCMOS33 } [get_ports { ck_io25 }]; #IO_L8N_T1_AD14N_35 Sch=ad_n[14] ChipKit pin=A11 + +## ChipKit SPI +#set_property -dict { PACKAGE_PIN G1 IOSTANDARD LVCMOS33 } [get_ports { ck_miso }]; #IO_L17N_T2_35 Sch=ck_miso +#set_property -dict { PACKAGE_PIN H1 IOSTANDARD LVCMOS33 } [get_ports { ck_mosi }]; #IO_L17P_T2_35 Sch=ck_mosi +#set_property -dict { PACKAGE_PIN F1 IOSTANDARD LVCMOS33 } [get_ports { ck_sck }]; #IO_L18P_T2_35 Sch=ck_sck +#set_property -dict { PACKAGE_PIN C1 IOSTANDARD LVCMOS33 } [get_ports { ck_ss }]; #IO_L16N_T2_35 Sch=ck_ss + +## ChipKit I2C +#set_property -dict { PACKAGE_PIN L18 IOSTANDARD LVCMOS33 } [get_ports { ck_scl }]; #IO_L4P_T0_D04_14 Sch=ck_scl +#set_property -dict { PACKAGE_PIN M18 IOSTANDARD LVCMOS33 } [get_ports { ck_sda }]; #IO_L4N_T0_D05_14 Sch=ck_sda +#set_property -dict { PACKAGE_PIN A14 IOSTANDARD LVCMOS33 } [get_ports { scl_pup }]; #IO_L9N_T1_DQS_AD3N_15 Sch=scl_pup +#set_property -dict { PACKAGE_PIN A13 IOSTANDARD LVCMOS33 } [get_ports { sda_pup }]; #IO_L9P_T1_DQS_AD3P_15 Sch=sda_pup + +## Misc. ChipKit Ports +#set_property -dict { PACKAGE_PIN M17 IOSTANDARD LVCMOS33 } [get_ports { ck_ioa }]; #IO_L10N_T1_D15_14 Sch=ck_ioa +set_property -dict {PACKAGE_PIN C2 IOSTANDARD LVCMOS33} [get_ports rst] + +## SMSC Ethernet PHY +#set_property -dict { PACKAGE_PIN D17 IOSTANDARD LVCMOS33 } [get_ports { eth_col }]; #IO_L16N_T2_A27_15 Sch=eth_col +#set_property -dict { PACKAGE_PIN G14 IOSTANDARD LVCMOS33 } [get_ports { eth_crs }]; #IO_L15N_T2_DQS_ADV_B_15 Sch=eth_crs +#set_property -dict { PACKAGE_PIN F16 IOSTANDARD LVCMOS33 } [get_ports { eth_mdc }]; #IO_L14N_T2_SRCC_15 Sch=eth_mdc +#set_property -dict { PACKAGE_PIN K13 IOSTANDARD LVCMOS33 } [get_ports { eth_mdio }]; #IO_L17P_T2_A26_15 Sch=eth_mdio +#set_property -dict { PACKAGE_PIN G18 IOSTANDARD LVCMOS33 } [get_ports { eth_ref_clk }]; #IO_L22P_T3_A17_15 Sch=eth_ref_clk +#set_property -dict { PACKAGE_PIN C16 IOSTANDARD LVCMOS33 } [get_ports { eth_rstn }]; #IO_L20P_T3_A20_15 Sch=eth_rstn +#set_property -dict { PACKAGE_PIN F15 IOSTANDARD LVCMOS33 } [get_ports { eth_rx_clk }]; #IO_L14P_T2_SRCC_15 Sch=eth_rx_clk +#set_property -dict { PACKAGE_PIN G16 IOSTANDARD LVCMOS33 } [get_ports { eth_rx_dv }]; #IO_L13N_T2_MRCC_15 Sch=eth_rx_dv +#set_property -dict { PACKAGE_PIN D18 IOSTANDARD LVCMOS33 } [get_ports { eth_rxd[0] }]; #IO_L21N_T3_DQS_A18_15 Sch=eth_rxd[0] +#set_property -dict { PACKAGE_PIN E17 IOSTANDARD LVCMOS33 } [get_ports { eth_rxd[1] }]; #IO_L16P_T2_A28_15 Sch=eth_rxd[1] +#set_property -dict { PACKAGE_PIN E18 IOSTANDARD LVCMOS33 } [get_ports { eth_rxd[2] }]; #IO_L21P_T3_DQS_15 Sch=eth_rxd[2] +#set_property -dict { PACKAGE_PIN G17 IOSTANDARD LVCMOS33 } [get_ports { eth_rxd[3] }]; #IO_L18N_T2_A23_15 Sch=eth_rxd[3] +#set_property -dict { PACKAGE_PIN C17 IOSTANDARD LVCMOS33 } [get_ports { eth_rxerr }]; #IO_L20N_T3_A19_15 Sch=eth_rxerr +#set_property -dict { PACKAGE_PIN H16 IOSTANDARD LVCMOS33 } [get_ports { eth_tx_clk }]; #IO_L13P_T2_MRCC_15 Sch=eth_tx_clk +#set_property -dict { PACKAGE_PIN H15 IOSTANDARD LVCMOS33 } [get_ports { eth_tx_en }]; #IO_L19N_T3_A21_VREF_15 Sch=eth_tx_en +#set_property -dict { PACKAGE_PIN H14 IOSTANDARD LVCMOS33 } [get_ports { eth_txd[0] }]; #IO_L15P_T2_DQS_15 Sch=eth_txd[0] +#set_property -dict { PACKAGE_PIN J14 IOSTANDARD LVCMOS33 } [get_ports { eth_txd[1] }]; #IO_L19P_T3_A22_15 Sch=eth_txd[1] +#set_property -dict { PACKAGE_PIN J13 IOSTANDARD LVCMOS33 } [get_ports { eth_txd[2] }]; #IO_L17N_T2_A25_15 Sch=eth_txd[2] +#set_property -dict { PACKAGE_PIN H17 IOSTANDARD LVCMOS33 } [get_ports { eth_txd[3] }]; #IO_L18P_T2_A24_15 Sch=eth_txd[3] + +## Quad SPI Flash +#set_property -dict { PACKAGE_PIN L13 IOSTANDARD LVCMOS33 } [get_ports { qspi_cs }]; #IO_L6P_T0_FCS_B_14 Sch=qspi_cs +#set_property -dict { PACKAGE_PIN K17 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[0] }]; #IO_L1P_T0_D00_MOSI_14 Sch=qspi_dq[0] +#set_property -dict { PACKAGE_PIN K18 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[1] }]; #IO_L1N_T0_D01_DIN_14 Sch=qspi_dq[1] +#set_property -dict { PACKAGE_PIN L14 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[2] }]; #IO_L2P_T0_D02_14 Sch=qspi_dq[2] +#set_property -dict { PACKAGE_PIN M14 IOSTANDARD LVCMOS33 } [get_ports { qspi_dq[3] }]; #IO_L2N_T0_D03_14 Sch=qspi_dq[3] + +## Power Measurements +#set_property -dict { PACKAGE_PIN B17 IOSTANDARD LVCMOS33 } [get_ports { vsnsvu_n }]; #IO_L7N_T1_AD2N_15 Sch=ad_n[2] +#set_property -dict { PACKAGE_PIN B16 IOSTANDARD LVCMOS33 } [get_ports { vsnsvu_p }]; #IO_L7P_T1_AD2P_15 Sch=ad_p[2] +#set_property -dict { PACKAGE_PIN B12 IOSTANDARD LVCMOS33 } [get_ports { vsns5v0_n }]; #IO_L3N_T0_DQS_AD1N_15 Sch=ad_n[1] +#set_property -dict { PACKAGE_PIN C12 IOSTANDARD LVCMOS33 } [get_ports { vsns5v0_p }]; #IO_L3P_T0_DQS_AD1P_15 Sch=ad_p[1] +#set_property -dict { PACKAGE_PIN F14 IOSTANDARD LVCMOS33 } [get_ports { isns5v0_n }]; #IO_L5N_T0_AD9N_15 Sch=ad_n[9] +#set_property -dict { PACKAGE_PIN F13 IOSTANDARD LVCMOS33 } [get_ports { isns5v0_p }]; #IO_L5P_T0_AD9P_15 Sch=ad_p[9] +#set_property -dict { PACKAGE_PIN A16 IOSTANDARD LVCMOS33 } [get_ports { isns0v95_n }]; #IO_L8N_T1_AD10N_15 Sch=ad_n[10] +#set_property -dict { PACKAGE_PIN A15 IOSTANDARD LVCMOS33 } [get_ports { isns0v95_p }]; #IO_L8P_T1_AD10P_15 Sch=ad_p[10] + +set_property BITSTREAM.GENERAL.COMPRESS True [current_design] diff --git a/rtl/arty-a7/Arty_C_mig.ucf b/rtl/arty-a7/Arty_C_mig.ucf new file mode 100644 index 0000000..5a36c18 --- /dev/null +++ b/rtl/arty-a7/Arty_C_mig.ucf @@ -0,0 +1,48 @@ +NET "ddr3_dq[0]" LOC = "K5" | IOSTANDARD = SSTL135 ; +NET "ddr3_dq[1]" LOC = "L3" | IOSTANDARD = SSTL135 ; +NET "ddr3_dq[2]" LOC = "K3" | IOSTANDARD = SSTL135 ; +NET "ddr3_dq[3]" LOC = "L6" | IOSTANDARD = SSTL135 ; +NET "ddr3_dq[4]" LOC = "M3" | IOSTANDARD = SSTL135 ; +NET "ddr3_dq[5]" LOC = "M1" | IOSTANDARD = SSTL135 ; +NET "ddr3_dq[6]" LOC = "L4" | IOSTANDARD = SSTL135 ; +NET "ddr3_dq[7]" LOC = "M2" | IOSTANDARD = SSTL135 ; +NET "ddr3_dq[8]" LOC = "V4" | IOSTANDARD = SSTL135 ; +NET "ddr3_dq[9]" LOC = "T5" | IOSTANDARD = SSTL135 ; +NET "ddr3_dq[10]" LOC = "U4" | IOSTANDARD = SSTL135 ; +NET "ddr3_dq[11]" LOC = "V5" | IOSTANDARD = SSTL135 ; +NET "ddr3_dq[12]" LOC = "V1" | IOSTANDARD = SSTL135 ; +NET "ddr3_dq[13]" LOC = "T3" | IOSTANDARD = SSTL135 ; +NET "ddr3_dq[14]" LOC = "U3" | IOSTANDARD = SSTL135 ; +NET "ddr3_dq[15]" LOC = "R3" | IOSTANDARD = SSTL135 ; +NET "ddr3_dm[0]" LOC = "L1" | IOSTANDARD = SSTL135 ; +NET "ddr3_dm[1]" LOC = "U1" | IOSTANDARD = SSTL135 ; +NET "ddr3_dqs_p[0]" LOC = "N2" | IOSTANDARD = DIFF_SSTL135 ; +NET "ddr3_dqs_n[0]" LOC = "N1" | IOSTANDARD = DIFF_SSTL135 ; +NET "ddr3_dqs_p[1]" LOC = "U2" | IOSTANDARD = DIFF_SSTL135 ; +NET "ddr3_dqs_n[1]" LOC = "V2" | IOSTANDARD = DIFF_SSTL135 ; +NET "ddr3_addr[13]" LOC = "T8" | IOSTANDARD = SSTL135 ; +NET "ddr3_addr[12]" LOC = "T6" | IOSTANDARD = SSTL135 ; +NET "ddr3_addr[11]" LOC = "U6" | IOSTANDARD = SSTL135 ; +NET "ddr3_addr[10]" LOC = "R6" | IOSTANDARD = SSTL135 ; +NET "ddr3_addr[9]" LOC = "V7" | IOSTANDARD = SSTL135 ; +NET "ddr3_addr[8]" LOC = "R8" | IOSTANDARD = SSTL135 ; +NET "ddr3_addr[7]" LOC = "U7" | IOSTANDARD = SSTL135 ; +NET "ddr3_addr[6]" LOC = "V6" | IOSTANDARD = SSTL135 ; +NET "ddr3_addr[5]" LOC = "R7" | IOSTANDARD = SSTL135 ; +NET "ddr3_addr[4]" LOC = "N6" | IOSTANDARD = SSTL135 ; +NET "ddr3_addr[3]" LOC = "T1" | IOSTANDARD = SSTL135 ; +NET "ddr3_addr[2]" LOC = "N4" | IOSTANDARD = SSTL135 ; +NET "ddr3_addr[1]" LOC = "M6" | IOSTANDARD = SSTL135 ; +NET "ddr3_addr[0]" LOC = "R2" | IOSTANDARD = SSTL135 ; +NET "ddr3_ba[2]" LOC = "P2" | IOSTANDARD = SSTL135 ; +NET "ddr3_ba[1]" LOC = "P4" | IOSTANDARD = SSTL135 ; +NET "ddr3_ba[0]" LOC = "R1" | IOSTANDARD = SSTL135 ; +NET "ddr3_ck_p[0]" LOC = "U9" | IOSTANDARD = DIFF_SSTL135 ; +NET "ddr3_ck_n[0]" LOC = "V9" | IOSTANDARD = DIFF_SSTL135 ; +NET "ddr3_ras_n" LOC = "P3" | IOSTANDARD = SSTL135 ; +NET "ddr3_cas_n" LOC = "M4" | IOSTANDARD = SSTL135 ; +NET "ddr3_we_n" LOC = "P5" | IOSTANDARD = SSTL135 ; +NET "ddr3_reset_n" LOC = "K6" | IOSTANDARD = SSTL135 ; +NET "ddr3_cke[0]" LOC = "N5" | IOSTANDARD = SSTL135 ; +NET "ddr3_odt[0]" LOC = "R5" | IOSTANDARD = SSTL135 ; +NET "ddr3_cs_n[0]" LOC = "U8" | IOSTANDARD = SSTL135 ; diff --git a/rtl/arty-a7/mig_dram_0/mig_a.prj b/rtl/arty-a7/mig_dram_0/mig_a.prj new file mode 100644 index 0000000..b263a25 --- /dev/null +++ b/rtl/arty-a7/mig_dram_0/mig_a.prj @@ -0,0 +1,148 @@ + + + + + + + + mig_dram_0 + + 1 + + 1 + + OFF + + 1024 + + ON + + Enabled + + xc7a35ti-csg324/-1L + + 4.2 + + No Buffer + + No Buffer + + ACTIVE LOW + + FALSE + + 1 + + 50 Ohms + + 0 + + + DDR3_SDRAM/Components/MT41K128M16XX-15E + 3000 + 1.8V + 4:1 + 83.333 + 0 + 666 + 1.000 + 1 + 1 + 1 + 1 + 16 + 1 + 1 + Disabled + Strict + 4 + FALSE + + 14 + 10 + 3 + 1.35V + BANK_ROW_COLUMN + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 8 - Fixed + Sequential + 5 + Normal + No + Slow Exit + Enable + RZQ/6 + Disable + Enable + RZQ/6 + 0 + Disabled + Enabled + Output Buffer Enabled + Full Array + 5 + Enabled + Normal + Dynamic ODT off + NATIVE + + + + diff --git a/rtl/arty-a7/mig_dram_0/mig_b.prj b/rtl/arty-a7/mig_dram_0/mig_b.prj new file mode 100644 index 0000000..b263a25 --- /dev/null +++ b/rtl/arty-a7/mig_dram_0/mig_b.prj @@ -0,0 +1,148 @@ + + + + + + + + mig_dram_0 + + 1 + + 1 + + OFF + + 1024 + + ON + + Enabled + + xc7a35ti-csg324/-1L + + 4.2 + + No Buffer + + No Buffer + + ACTIVE LOW + + FALSE + + 1 + + 50 Ohms + + 0 + + + DDR3_SDRAM/Components/MT41K128M16XX-15E + 3000 + 1.8V + 4:1 + 83.333 + 0 + 666 + 1.000 + 1 + 1 + 1 + 1 + 16 + 1 + 1 + Disabled + Strict + 4 + FALSE + + 14 + 10 + 3 + 1.35V + BANK_ROW_COLUMN + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 8 - Fixed + Sequential + 5 + Normal + No + Slow Exit + Enable + RZQ/6 + Disable + Enable + RZQ/6 + 0 + Disabled + Enabled + Output Buffer Enabled + Full Array + 5 + Enabled + Normal + Dynamic ODT off + NATIVE + + + + diff --git a/rtl/arty-a7/mig_dram_0/mig_dram_0.xci b/rtl/arty-a7/mig_dram_0/mig_dram_0.xci new file mode 100644 index 0000000..3da3694 --- /dev/null +++ b/rtl/arty-a7/mig_dram_0/mig_dram_0.xci @@ -0,0 +1,2876 @@ + + + xilinx.com + xci + unknown + 1.0 + + + mig_dram_0 + + + 0 + 0 + + 0 + 0 + TDM + 8 + false + 11 + 11 + true + + true + 8 + + COMPONENTS + ROW_COLUMN_BANK + Single + 1250 + 0 + TDM + 8 + false + 11 + 11 + true + + true + 8 + + COMPONENTS + ROW_COLUMN_BANK + Single + 1250 + 0 + 0 + + + + 0 + 0 + + + + 0 + 0 + + + + 0 + 0 + + + + 0 + 0 + + + + 0 + 0 + 0 + 0 + 0 + 0 + false + 100000000 + + + + 100000000 + 0 + 0 + 0.000 + 0 + + 0 + 0 + TDM + 8 + false + 11 + 11 + true + + true + 8 + + COMPONENTS + ROW_COLUMN_BANK + Single + 1250 + 0 + TDM + 8 + false + 11 + 11 + true + + true + 8 + + COMPONENTS + ROW_COLUMN_BANK + Single + 1250 + 0 + 0 + + + + 0 + 0 + + + + 0 + 0 + + + + 0 + 0 + + + + 0 + 0 + + + + 0 + 0 + 0 + 0 + 0 + 0 + false + 100000000 + + + + 100000000 + 0 + 0 + 0.000 + 0 + + 0 + 0 + TDM + 8 + false + 11 + 11 + true + + true + 8 + + COMPONENTS + ROW_COLUMN_BANK + Single + 1250 + 0 + TDM + 8 + false + 11 + 11 + true + + true + 8 + + COMPONENTS + ROW_COLUMN_BANK + Single + 1250 + 0 + 0 + + + + 0 + 0 + + + + 0 + 0 + + + + 0 + 0 + + + + 0 + 0 + + + + 0 + 0 + 0 + 0 + 0 + 0 + false + 100000000 + + + + 100000000 + 0 + 0 + 0.000 + 0 + + 0 + 0 + TDM + 8 + false + 11 + 11 + true + + true + 8 + + COMPONENTS + ROW_COLUMN_BANK + Single + 1250 + 0 + TDM + 8 + false + 11 + 11 + true + + true + 8 + + COMPONENTS + ROW_COLUMN_BANK + Single + 1250 + 0 + 0 + + + + 0 + 0 + + + + 0 + 0 + + + + 0 + 0 + + + + 0 + 0 + + + + 0 + 0 + 0 + 0 + 0 + 0 + false + 100000000 + + + + 100000000 + 0 + 0 + 0.000 + 0 + + 0 + 0 + TDM + 8 + false + 11 + 11 + true + + true + 8 + + COMPONENTS + ROW_COLUMN_BANK + Single + 1250 + 0 + TDM + 8 + false + 11 + 11 + true + + true + 8 + + COMPONENTS + ROW_COLUMN_BANK + Single + 1250 + 0 + 0 + + + + 0 + 0 + + + + 0 + 0 + + + + 0 + 0 + + + + 0 + 0 + + + + 0 + 0 + 0 + 0 + 0 + 0 + false + 100000000 + + + + 100000000 + 0 + 0 + 0.000 + 0 + + 0 + 0 + TDM + 8 + false + 11 + 11 + true + + true + 8 + + COMPONENTS + ROW_COLUMN_BANK + Single + 1250 + 0 + TDM + 8 + false + 11 + 11 + true + + true + 8 + + COMPONENTS + ROW_COLUMN_BANK + Single + 1250 + 0 + 0 + + + + 0 + 0 + + + + 0 + 0 + + + + 0 + 0 + + + + 0 + 0 + + + + 0 + 0 + 0 + 0 + 0 + 0 + false + 100000000 + + + + 100000000 + 0 + 0 + 0.000 + 0 + + 0 + 0 + TDM + 8 + false + 11 + 11 + true + + true + 8 + + COMPONENTS + ROW_COLUMN_BANK + Single + 1250 + 0 + TDM + 8 + false + 11 + 11 + true + + true + 8 + + COMPONENTS + ROW_COLUMN_BANK + Single + 1250 + 0 + 0 + + + + 0 + 0 + + + + 0 + 0 + + + + 0 + 0 + + + + 0 + 0 + + + + 0 + 0 + 0 + 0 + 0 + 0 + false + 100000000 + + + + 100000000 + 0 + 0 + 0.000 + 0 + + 0 + 0 + TDM + 8 + false + 11 + 11 + true + + true + 8 + + COMPONENTS + ROW_COLUMN_BANK + Single + 1250 + 0 + TDM + 8 + false + 11 + 11 + true + + true + 8 + + COMPONENTS + ROW_COLUMN_BANK + Single + 1250 + 0 + 0 + + + + 0 + 0 + + + + 0 + 0 + + + + 0 + 0 + + + + 0 + 0 + + + + 0 + 0 + 0 + 0 + 0 + 0 + false + 100000000 + + + + 100000000 + 0 + 0 + 0.000 + false + 100000000 + + + + 100000000 + 0 + 0 + 0.000 + + 0 + 0 + TDM + 8 + false + 11 + 11 + true + + true + 8 + + COMPONENTS + ROW_COLUMN_BANK + Single + 1250 + 0 + TDM + 8 + false + 11 + 11 + true + + true + 8 + + COMPONENTS + ROW_COLUMN_BANK + Single + 1250 + 0 + 0 + + + + 0 + 0 + + + + 0 + 0 + + + + 0 + 0 + + + + 0 + 0 + + + + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 1 + 1 + 1 + 0.000 + AXI4LITE + READ_WRITE + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 1 + 1 + 1 + 0.000 + AXI4LITE + READ_WRITE + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 1 + 1 + 1 + 0.000 + AXI4LITE + READ_WRITE + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 1 + 1 + 1 + 0.000 + AXI4LITE + READ_WRITE + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 1 + 1 + 1 + 0.000 + AXI4LITE + READ_WRITE + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 1 + 1 + 1 + 0.000 + AXI4LITE + READ_WRITE + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 1 + 1 + 1 + 0.000 + AXI4LITE + READ_WRITE + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 1 + 1 + 1 + 0.000 + AXI4LITE + READ_WRITE + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 1 + 1 + 1 + 0.000 + AXI4LITE + READ_WRITE + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 1 + 1 + 1 + 0.000 + AXI4LITE + READ_WRITE + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 1 + 1 + 1 + 0.000 + AXI4LITE + READ_WRITE + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 1 + 1 + 1 + 0.000 + AXI4LITE + READ_WRITE + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 1 + 1 + 1 + 0.000 + AXI4LITE + READ_WRITE + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 1 + 1 + 1 + 0.000 + AXI4LITE + READ_WRITE + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 1 + 1 + 1 + 0.000 + AXI4LITE + READ_WRITE + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 1 + 1 + 1 + 0.000 + AXI4LITE + READ_WRITE + 0 + 0 + 0 + 0 + 0 + 0 + false + 100000000 + + + + 100000000 + 0 + 0 + 0.000 + 1 + 0 + 0 + 0 + + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 1 + 1 + 1 + 0.000 + AXI4LITE + READ_WRITE + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + 1 + 1 + 1 + 0.000 + AXI4LITE + READ_WRITE + 0 + 0 + 0 + 0 + 0 + 32 + 32 + 32 + 4 + 1048576 + 32 + 4 + 1048576 + 8 + 3 + 1 + 1 + 1 + 8 + OFF + 1 + 1 + 1 + 8 + 1 + OFF + 14 + 1 + 1 + 1 + 2 + 1 + 8 + 3 + 1 + 1 + 1 + 8 + OFF + 1 + 1 + 1 + 8 + 1 + OFF + 14 + 1 + 1 + 1 + 2 + 1 + 8 + 8 + 2 + OFF + 1 + OFF + 100.0 + FALSE + 8 + 3 + 1 + 1 + 1 + 8 + OFF + 1 + 1 + 1 + 8 + OFF + 14 + 1 + 1 + 1 + 2 + 1 + DDR3 + FALSE + 10.0 + FALSE + 10 + FALSE + 10 + FALSE + 10 + FALSE + 10 + 1200.0 + 0.000 + ACTIVE_LOW + 29 + 1 + 8 + 18 + OFF + 1 + 29 + 2 + 1 + 1 + 18 + OFF + 1 + 1 + 1 + 8 + 1 + 29 + 1 + 29 + 2 + 1 + 1 + 18 + OFF + 1 + 1 + 1 + 8 + 1 + 29 + 1 + 29 + 2 + 1 + 18 + 1 + 1 + DIFF + FALSE + 0 + 32 + 32 + 32 + 4 + 1048576 + 32 + 4 + 1048576 + 8 + 3 + 1 + 1 + 1 + 8 + OFF + 1 + 1 + 1 + 8 + 1 + OFF + 14 + 1 + 1 + 1 + 2 + 1 + 8 + 3 + 1 + 1 + 1 + 8 + OFF + 1 + 1 + 1 + 8 + 1 + OFF + 14 + 1 + 1 + 1 + 2 + 1 + 8 + 8 + 2 + OFF + 1 + OFF + 100.0 + FALSE + 8 + 3 + 1 + 1 + 1 + 8 + OFF + 1 + 1 + 1 + 8 + OFF + 14 + 1 + 1 + 1 + 2 + 1 + DDR3 + FALSE + 10.0 + FALSE + 10 + FALSE + 10 + FALSE + 10 + FALSE + 10 + 1200.0 + 0.000 + ACTIVE_LOW + 29 + 1 + 8 + 18 + OFF + 1 + 29 + 2 + 1 + 1 + 18 + OFF + 1 + 1 + 1 + 8 + 1 + 29 + 1 + 29 + 2 + 1 + 1 + 18 + OFF + 1 + 1 + 1 + 8 + 1 + 29 + 1 + 29 + 2 + 1 + 18 + 1 + 1 + DIFF + FALSE + 0 + 32 + 32 + 32 + 4 + 1048576 + 32 + 4 + 1048576 + 8 + 3 + 1 + 1 + 1 + 8 + OFF + 1 + 1 + 1 + 8 + 1 + OFF + 14 + 1 + 1 + 1 + 2 + 1 + 8 + 3 + 1 + 1 + 1 + 8 + OFF + 1 + 1 + 1 + 8 + 1 + OFF + 14 + 1 + 1 + 1 + 2 + 1 + 8 + 8 + 2 + OFF + 1 + OFF + 100.0 + FALSE + 8 + 3 + 1 + 1 + 1 + 8 + OFF + 1 + 1 + 1 + 8 + OFF + 14 + 1 + 1 + 1 + 2 + 1 + DDR3 + FALSE + 10.0 + FALSE + 10 + FALSE + 10 + FALSE + 10 + FALSE + 10 + 1200.0 + 0.000 + ACTIVE_LOW + 29 + 1 + 8 + 18 + OFF + 1 + 29 + 2 + 1 + 1 + 18 + OFF + 1 + 1 + 1 + 8 + 1 + 29 + 1 + 29 + 2 + 1 + 1 + 18 + OFF + 1 + 1 + 1 + 8 + 1 + 29 + 1 + 29 + 2 + 1 + 18 + 1 + 1 + DIFF + FALSE + 0 + 32 + 32 + 32 + 4 + 1048576 + 32 + 4 + 1048576 + 8 + 3 + 1 + 1 + 1 + 8 + OFF + 1 + 1 + 1 + 8 + 1 + OFF + 14 + 1 + 1 + 1 + 2 + 1 + 8 + 3 + 1 + 1 + 1 + 8 + OFF + 1 + 1 + 1 + 8 + 1 + OFF + 14 + 1 + 1 + 1 + 2 + 1 + 8 + 8 + 2 + OFF + 1 + OFF + 100.0 + FALSE + 8 + 3 + 1 + 1 + 1 + 8 + OFF + 1 + 1 + 1 + 8 + OFF + 14 + 1 + 1 + 1 + 2 + 1 + DDR3 + FALSE + 10.0 + FALSE + 10 + FALSE + 10 + FALSE + 10 + FALSE + 10 + 1200.0 + 0.000 + ACTIVE_LOW + 29 + 1 + 8 + 18 + OFF + 1 + 29 + 2 + 1 + 1 + 18 + OFF + 1 + 1 + 1 + 8 + 1 + 29 + 1 + 29 + 2 + 1 + 1 + 18 + OFF + 1 + 1 + 1 + 8 + 1 + 29 + 1 + 29 + 2 + 1 + 18 + 1 + 1 + DIFF + FALSE + 0 + 32 + 32 + 32 + 4 + 1048576 + 32 + 4 + 1048576 + 8 + 3 + 1 + 1 + 1 + 8 + OFF + 1 + 1 + 1 + 8 + 1 + OFF + 14 + 1 + 1 + 1 + 2 + 1 + 8 + 3 + 1 + 1 + 1 + 8 + OFF + 1 + 1 + 1 + 8 + 1 + OFF + 14 + 1 + 1 + 1 + 2 + 1 + 8 + 8 + 2 + OFF + 1 + OFF + 100.0 + FALSE + 8 + 3 + 1 + 1 + 1 + 8 + OFF + 1 + 1 + 1 + 8 + OFF + 14 + 1 + 1 + 1 + 2 + 1 + DDR3 + FALSE + 10.0 + FALSE + 10 + FALSE + 10 + FALSE + 10 + FALSE + 10 + 1200.0 + 0.000 + ACTIVE_LOW + 29 + 1 + 8 + 18 + OFF + 1 + 29 + 2 + 1 + 1 + 18 + OFF + 1 + 1 + 1 + 8 + 1 + 29 + 1 + 29 + 2 + 1 + 1 + 18 + OFF + 1 + 1 + 1 + 8 + 1 + 29 + 1 + 29 + 2 + 1 + 18 + 1 + 1 + DIFF + FALSE + 0 + 32 + 32 + 32 + 4 + 1048576 + 32 + 4 + 1048576 + 8 + 3 + 1 + 1 + 1 + 8 + OFF + 1 + 1 + 1 + 8 + 1 + OFF + 14 + 1 + 1 + 1 + 2 + 1 + 8 + 3 + 1 + 1 + 1 + 8 + OFF + 1 + 1 + 1 + 8 + 1 + OFF + 14 + 1 + 1 + 1 + 2 + 1 + 8 + 8 + 2 + OFF + 1 + OFF + 100.0 + FALSE + 8 + 3 + 1 + 1 + 1 + 8 + OFF + 1 + 1 + 1 + 8 + OFF + 14 + 1 + 1 + 1 + 2 + 1 + DDR3 + FALSE + 10.0 + FALSE + 10 + FALSE + 10 + FALSE + 10 + FALSE + 10 + 1200.0 + 0.000 + ACTIVE_LOW + 29 + 1 + 8 + 18 + OFF + 1 + 29 + 2 + 1 + 1 + 18 + OFF + 1 + 1 + 1 + 8 + 1 + 29 + 1 + 29 + 2 + 1 + 1 + 18 + OFF + 1 + 1 + 1 + 8 + 1 + 29 + 1 + 29 + 2 + 1 + 18 + 1 + 1 + DIFF + FALSE + 0 + 32 + 32 + 32 + 4 + 1048576 + 32 + 4 + 1048576 + 8 + 3 + 1 + 1 + 1 + 8 + OFF + 1 + 1 + 1 + 8 + 1 + OFF + 14 + 1 + 1 + 1 + 2 + 1 + 8 + 3 + 1 + 1 + 1 + 8 + OFF + 1 + 1 + 1 + 8 + 1 + OFF + 14 + 1 + 1 + 1 + 2 + 1 + 8 + 8 + 2 + OFF + 1 + OFF + 100.0 + FALSE + 8 + 3 + 1 + 1 + 1 + 8 + OFF + 1 + 1 + 1 + 8 + OFF + 14 + 1 + 1 + 1 + 2 + 1 + DDR3 + FALSE + 10.0 + FALSE + 10 + FALSE + 10 + FALSE + 10 + FALSE + 10 + 1200.0 + 0.000 + ACTIVE_LOW + 29 + 1 + 8 + 18 + OFF + 1 + 29 + 2 + 1 + 1 + 18 + OFF + 1 + 1 + 1 + 8 + 1 + 29 + 1 + 29 + 2 + 1 + 1 + 18 + OFF + 1 + 1 + 1 + 8 + 1 + 29 + 1 + 29 + 2 + 1 + 18 + 1 + 1 + DIFF + FALSE + 0 + 32 + 32 + 32 + 4 + 1048576 + 32 + 4 + 1048576 + 8 + 3 + 1 + 1 + 1 + 8 + OFF + 1 + 1 + 1 + 8 + 1 + OFF + 14 + 1 + 1 + 1 + 2 + 1 + 8 + 3 + 1 + 1 + 1 + 8 + OFF + 1 + 1 + 1 + 8 + 1 + OFF + 14 + 1 + 1 + 1 + 2 + 1 + 8 + 8 + 2 + OFF + 1 + OFF + 100.0 + FALSE + 8 + 3 + 1 + 1 + 1 + 8 + OFF + 1 + 1 + 1 + 8 + OFF + 14 + 1 + 1 + 1 + 2 + 1 + DDR3 + FALSE + 10.0 + FALSE + 10 + FALSE + 10 + FALSE + 10 + FALSE + 10 + 1200.0 + 0.000 + ACTIVE_LOW + 29 + 1 + 8 + 18 + OFF + 1 + 29 + 2 + 1 + 1 + 18 + OFF + 1 + 1 + 1 + 8 + 1 + 29 + 1 + 29 + 2 + 1 + 1 + 18 + OFF + 1 + 1 + 1 + 8 + 1 + 29 + 1 + 29 + 2 + 1 + 18 + 1 + 1 + DIFF + FALSE + 0 + 0 + 28 + 32 + 32 + 4 + 1048576 + 128 + 2 + 268435456 + 8 + 3 + 1 + 1 + 1 + 8 + OFF + 1 + 1 + 1 + 8 + 1 + OFF + 14 + 1 + 1 + 1 + 2 + 1 + 28 + 3 + 1 + 1 + 1 + 16 + OFF + 2 + 1 + 2 + 16 + 1 + OFF + 14 + 1 + 1 + 1 + 4 + 1 + 8 + 8 + 2 + OFF + 1 + OFF + 83333333 + FALSE + 8 + 3 + 1 + 1 + 1 + 8 + OFF + 1 + 1 + 1 + 8 + OFF + 14 + 1 + 1 + 1 + 2 + 1 + DDR3 + FALSE + 10.0 + FALSE + 10 + FALSE + 10 + FALSE + 10 + FALSE + 10 + 666 + 1 + 0.000 + ACTIVE_LOW + 29 + 1 + 8 + 18 + OFF + 1 + NOBUF + 29 + 2 + 1 + 1 + 18 + OFF + 1 + 1 + 1 + 8 + 1 + 29 + 1 + 29 + 2 + 1 + 1 + 18 + OFF + 1 + 1 + 1 + 8 + 1 + 29 + 1 + 29 + 2 + 1 + 18 + 1 + 1 + NOBUF + INTERNAL + FALSE + 0 + Custom + mig_dram_0 + Custom + Custom + mig_b.prj + artix7 + digilentinc.com:arty-a7-35:part0:1.0 + + xc7a35ti + csg324 + VERILOG + + MIXED + -1L + + I + TRUE + TRUE + IP_Flow + 1 + TRUE + . + + . + 2020.1 + OUT_OF_CONTEXT + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/rtl/arty-a7/sdspi_testbench_behav.wcfg b/rtl/arty-a7/sdspi_testbench_behav.wcfg new file mode 100644 index 0000000..bb29917 --- /dev/null +++ b/rtl/arty-a7/sdspi_testbench_behav.wcfg @@ -0,0 +1,176 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + clk + clk + + + tx_data[7:0] + tx_data[7:0] + + + rx_data[7:0] + rx_data[7:0] + + + rx_shifter[7:0] + rx_shifter[7:0] + + + tx_shifter[7:0] + tx_shifter[7:0] + + + tx_fifo_out[7:0] + tx_fifo_out[7:0] + + + tx_fifo_rd_en + tx_fifo_rd_en + + + tx_fifo_wr_en + tx_fifo_wr_en + + + rx_fifo_wr_en + rx_fifo_wr_en + + + rx_bit_recvd + rx_bit_recvd + + + tail_x[4:0] + tail_x[4:0] + + + head_x[4:0] + head_x[4:0] + + + tx_ready + tx_ready + + + tx_empty + tx_empty + + + rx_avail + rx_avail + + + tx_write + tx_write + + + rx_read + rx_read + + + ctrl_write + ctrl_write + + + rx_filter_en + rx_filter_en + + + txrx_en + txrx_en + + + spiclk_div_wr + spiclk_div_wr + + + spi_clk_on + spi_clk_on + + + spiclk_f_en + spiclk_f_en + + + spi_clk_f_on + spi_clk_f_on + + + sd_cs_n + sd_cs_n + #DCDCDC + true + + + sd_mosi + sd_mosi + #00FFFF + true + + + sd_miso + sd_miso + + + sd_sck + sd_sck + #FFFF00 + true + + + xcvr_on + xcvr_on + + + hphase_start + hphase_start + #F0E68C + true + + + clk_phase[1:0] + clk_phase[1:0] + #D2691E + true + + + running + running + + + xcvr_bitcount[3:0] + xcvr_bitcount[3:0] + + + spi_clk_count[6:0] + spi_clk_count[6:0] + + + spi_clk_div[6:0] + spi_clk_div[6:0] + + diff --git a/rtl/arty-a7/testbench_behav1.wcfg b/rtl/arty-a7/testbench_behav1.wcfg new file mode 100644 index 0000000..1a2bc03 --- /dev/null +++ b/rtl/arty-a7/testbench_behav1.wcfg @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + clk + clk + + + addr[31:0] + addr[31:0] + + + data_in[31:0] + data_in[31:0] + + + data_out[31:0] + data_out[31:0] + + + seq_state[1:0] + seq_state[1:0] + + + PC[31:0] + PC[31:0] + + + nPC[31:0] + nPC[31:0] + + + ins[15:0] + ins[15:0] + BINARYRADIX + + + ins_branch + ins_branch + + + ins_loadrel + ins_loadrel + + + X[31:0] + X[31:0] + + + nX[31:0] + nX[31:0] + + + FP[31:0] + FP[31:0] + + + pc_next_ins[31:0] + pc_next_ins[31:0] + + + mem_wait + mem_wait + + + ins_buf[15:0] + ins_buf[15:0] + + diff --git a/rtl/arty-a7/tridoracpu.tcl b/rtl/arty-a7/tridoracpu.tcl new file mode 100644 index 0000000..e18483e --- /dev/null +++ b/rtl/arty-a7/tridoracpu.tcl @@ -0,0 +1,724 @@ +#***************************************************************************************** +# Vivado (TM) v2020.1 (64-bit) +# +# tridoracpu.tcl: Tcl script for re-creating project 'tridoracpu' +# +# Generated by Vivado on Sat Sep 14 23:58:12 +0200 2024 +# IP Build 2902112 on Wed May 27 22:43:36 MDT 2020 +# +# This file contains the Vivado Tcl commands for re-creating the project to the state* +# when this script was generated. In order to re-create the project, please source this +# file in the Vivado Tcl Shell. +# +# * Note that the runs in the created project will be configured the same way as the +# original project, however they will not be launched automatically. To regenerate the +# run results please launch the synthesis/implementation runs as needed. +# +#***************************************************************************************** +# NOTE: In order to use this script for source control purposes, please make sure that the +# following files are added to the source control system:- +# +# 1. This project restoration tcl script (tridoracpu.tcl) that was generated. +# +# 2. The following source(s) files that were local or imported into the original project. +# (Please see the '$orig_proj_dir' and '$origin_dir' variable setting below at the start of the script) +# +# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/cpuclk.v" +# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/display_clock.v" +# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/mem.v" +# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/stack.v" +# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/stackcpu.v" +# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/vgafb.v" +# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/top.v" +# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/testbench.v" +# "C:/Users/sebastian/develop/fpga/tridoracpu/rom.mem" +# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/ip/mig_dram_0/mig_a.prj" +# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/ip/mig_dram_0/mig_b.prj" +# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/dram_bridge.v" +# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/sdspi.v" +# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/bram_tdp.v" +# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/palette.v" +# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/irqctrl.v" +# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/fifo.v" +# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/fifo_testbench.v" +# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/sdspi_testbench.v" +# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/ip/mig_dram_0/mig_dram_0.xci" +# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sim_1/new/uart_tb.v" +# "C:/Users/sebastian/develop/fpga/tridoracpu/testbench_behav1.wcfg" +# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/fifo.v" +# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/new/fifo_testbench.v" +# "C:/Users/sebastian/develop/fpga/tridoracpu/sdspi_testbench_behav.wcfg" +# +# 3. The following remote source files that were added to the original project:- +# +# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/sources_1/imports/verilog/uart.v" +# "C:/Users/sebastian/develop/fpga/tridoracpu/tridoracpu.srcs/constrs_1/imports/fpga/Arty-A7-35-Master.xdc" +# +#***************************************************************************************** + +#xhub::refresh_catalog [xhub::get_xstores xilinx_board_store] +# this will take quite some time +#xhub::install [xhub::get_xitems] + +# Set the reference directory for source file relative paths (by default the value is script directory path) +set origin_dir "C:/Users/sebastian/develop/Tridora/rtl" + +# Oh come on, Xilinx, why? +#set xilinx_board_store_dir "../../../../AppData/Roaming/Xilinx/Vivado/2020.1/xhub/board_store/xilinx_board_store" +set xilinx_board_store_dir [get_property LOCAL_ROOT_DIR [xhub::get_xstores xilinx_board_store]] +set_param board.repoPaths [get_property LOCAL_ROOT_DIR [xhub::get_xstores xilinx_board_store]] + +# Use origin directory path location variable, if specified in the tcl shell +if { [info exists ::origin_dir_loc] } { + set origin_dir $::origin_dir_loc +} + +# Set the project name +set _xil_proj_name_ "tridoracpu" + +# Use project name variable, if specified in the tcl shell +if { [info exists ::user_project_name] } { + set _xil_proj_name_ $::user_project_name +} + +variable script_file +set script_file "tridoracpu.tcl" + +# Help information for this script +proc print_help {} { + variable script_file + puts "\nDescription:" + puts "Recreate a Vivado project from this script. The created project will be" + puts "functionally equivalent to the original project for which this script was" + puts "generated. The script contains commands for creating a project, filesets," + puts "runs, adding/importing sources and setting properties on various objects.\n" + puts "Syntax:" + puts "$script_file" + puts "$script_file -tclargs \[--origin_dir \]" + puts "$script_file -tclargs \[--project_name \]" + puts "$script_file -tclargs \[--help\]\n" + puts "Usage:" + puts "Name Description" + puts "-------------------------------------------------------------------------" + puts "\[--origin_dir \] Determine source file paths wrt this path. Default" + puts " origin_dir path value is \".\", otherwise, the value" + puts " that was set with the \"-paths_relative_to\" switch" + puts " when this script was generated.\n" + puts "\[--project_name \] Create project with the specified name. Default" + puts " name is the name of the project from where this" + puts " script was generated.\n" + puts "\[--help\] Print help information for this script" + puts "-------------------------------------------------------------------------\n" + exit 0 +} + +if { $::argc > 0 } { + for {set i 0} {$i < $::argc} {incr i} { + set option [string trim [lindex $::argv $i]] + switch -regexp -- $option { + "--origin_dir" { incr i; set origin_dir [lindex $::argv $i] } + "--project_name" { incr i; set _xil_proj_name_ [lindex $::argv $i] } + "--help" { print_help } + default { + if { [regexp {^-} $option] } { + puts "ERROR: Unknown option '$option' specified, please type '$script_file -tclargs --help' for usage info.\n" + return 1 + } + } + } + } +} + +# Set the directory path for the original project from where this script was exported +set orig_proj_dir "[file normalize "${origin_dir}/arty-a7"]" + +# Create project +create_project ${_xil_proj_name_} ./${_xil_proj_name_} -part xc7a35ticsg324-1L + +# Set the directory path for the new project +set proj_dir [get_property directory [current_project]] + +# Set project properties +set obj [current_project] +#set_property -name "board_part_repo_paths" -value "[file normalize "$xilinx_board_store_dir"]" -objects $obj +set_property -name "board_part" -value "digilentinc.com:arty-a7-35:part0:1.0" -objects $obj +set_property -name "default_lib" -value "xil_defaultlib" -objects $obj +set_property -name "enable_vhdl_2008" -value "1" -objects $obj +set_property -name "ip_cache_permissions" -value "read write" -objects $obj +set_property -name "ip_output_repo" -value "$proj_dir/${_xil_proj_name_}.cache/ip" -objects $obj +set_property -name "mem.enable_memory_map_generation" -value "1" -objects $obj +set_property -name "platform.board_id" -value "arty-a7-35" -objects $obj +set_property -name "sim.central_dir" -value "$proj_dir/${_xil_proj_name_}.ip_user_files" -objects $obj +set_property -name "sim.ip.auto_export_scripts" -value "1" -objects $obj +set_property -name "simulator_language" -value "Mixed" -objects $obj +set_property -name "source_mgmt_mode" -value "DisplayOnly" -objects $obj +set_property -name "webtalk.activehdl_export_sim" -value "4" -objects $obj +set_property -name "webtalk.ies_export_sim" -value "4" -objects $obj +set_property -name "webtalk.modelsim_export_sim" -value "4" -objects $obj +set_property -name "webtalk.questa_export_sim" -value "4" -objects $obj +set_property -name "webtalk.riviera_export_sim" -value "4" -objects $obj +set_property -name "webtalk.vcs_export_sim" -value "4" -objects $obj +set_property -name "webtalk.xsim_export_sim" -value "4" -objects $obj +set_property -name "webtalk.xsim_launch_sim" -value "537" -objects $obj + +# Create 'sources_1' fileset (if not found) +if {[string equal [get_filesets -quiet sources_1] ""]} { + create_fileset -srcset sources_1 +} + +# Set 'sources_1' fileset object +set obj [get_filesets sources_1] +set files [list \ + [file normalize "${origin_dir}/src/uart.v"] \ +] +add_files -norecurse -fileset $obj $files + +# Add local files from the original project (-no_copy_sources specified) +set files [list \ + [file normalize "${origin_dir}/src/cpuclk.v" ]\ + [file normalize "${origin_dir}/src/display_clock.v" ]\ + [file normalize "${origin_dir}/src/mem.v" ]\ + [file normalize "${origin_dir}/src/stack.v" ]\ + [file normalize "${origin_dir}/src/stackcpu.v" ]\ + [file normalize "${origin_dir}/src/vgafb.v" ]\ + [file normalize "${origin_dir}/src/top.v" ]\ + [file normalize "${origin_dir}/src/testbench.v" ]\ + [file normalize "${orig_proj_dir}/rom.mem" ]\ + [file normalize "${orig_proj_dir}/mig_dram_0/mig_a.prj" ]\ + [file normalize "${orig_proj_dir}/mig_dram_0/mig_b.prj" ]\ + [file normalize "${origin_dir}/src/dram_bridge.v" ]\ + [file normalize "${origin_dir}/src/sdspi.v" ]\ + [file normalize "${origin_dir}/src/bram_tdp.v" ]\ + [file normalize "${origin_dir}/src/palette.v" ]\ + [file normalize "${origin_dir}/src/irqctrl.v" ]\ + [file normalize "${origin_dir}/src/fifo.v" ]\ + [file normalize "${origin_dir}/src/fifo_testbench.v" ]\ + [file normalize "${origin_dir}/src/sdspi_testbench.v" ]\ +] +set added_files [add_files -fileset sources_1 $files] + +# Set 'sources_1' fileset file properties for remote files +set file "$origin_dir/src/uart.v" +set file [file normalize $file] +set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] +set_property -name "used_in" -value "synthesis implementation" -objects $file_obj +set_property -name "used_in_simulation" -value "0" -objects $file_obj + + +# Set 'sources_1' fileset file properties for local files +set file "src/cpuclk.v" +set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] +set_property -name "used_in" -value "synthesis implementation" -objects $file_obj +set_property -name "used_in_simulation" -value "0" -objects $file_obj + +set file "src/display_clock.v" +set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] +set_property -name "is_enabled" -value "0" -objects $file_obj + +set file "src/mem.v" +set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] +set_property -name "used_in" -value "synthesis implementation" -objects $file_obj +set_property -name "used_in_simulation" -value "0" -objects $file_obj + +set file "src/stack.v" +set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] +set_property -name "used_in" -value "synthesis implementation" -objects $file_obj +set_property -name "used_in_simulation" -value "0" -objects $file_obj + +set file "src/stackcpu.v" +set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] +set_property -name "used_in" -value "synthesis implementation" -objects $file_obj +set_property -name "used_in_simulation" -value "0" -objects $file_obj + +set file "src/vgafb.v" +set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] +set_property -name "used_in" -value "synthesis implementation" -objects $file_obj +set_property -name "used_in_simulation" -value "0" -objects $file_obj + +set file "src/top.v" +set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] +set_property -name "used_in" -value "synthesis implementation" -objects $file_obj +set_property -name "used_in_simulation" -value "0" -objects $file_obj + +set file "src/testbench.v" +set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] +set_property -name "used_in" -value "" -objects $file_obj +set_property -name "used_in_implementation" -value "0" -objects $file_obj +set_property -name "used_in_simulation" -value "0" -objects $file_obj +set_property -name "used_in_synthesis" -value "0" -objects $file_obj + +set file "arty-a7/rom.mem" +set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] +set_property -name "file_type" -value "Memory File" -objects $file_obj + +set file "arty-a7/mig_dram_0/mig_a.prj" +set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] +set_property -name "scoped_to_cells" -value "mig_dram_0" -objects $file_obj + +set file "arty-a7/mig_dram_0/mig_b.prj" +set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] +set_property -name "scoped_to_cells" -value "mig_dram_0" -objects $file_obj + +set file "src/dram_bridge.v" +set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] +set_property -name "used_in" -value "synthesis implementation" -objects $file_obj +set_property -name "used_in_simulation" -value "0" -objects $file_obj + +set file "src/palette.v" +set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] +set_property -name "used_in" -value "synthesis implementation" -objects $file_obj +set_property -name "used_in_simulation" -value "0" -objects $file_obj + +set file "src/irqctrl.v" +set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] +set_property -name "used_in" -value "synthesis implementation" -objects $file_obj +set_property -name "used_in_simulation" -value "0" -objects $file_obj + +set file "src/fifo_testbench.v" +set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] +set_property -name "used_in" -value "" -objects $file_obj +set_property -name "used_in_implementation" -value "0" -objects $file_obj +set_property -name "used_in_simulation" -value "0" -objects $file_obj +set_property -name "used_in_synthesis" -value "0" -objects $file_obj + + +# Set 'sources_1' fileset properties +set obj [get_filesets sources_1] +set_property -name "top" -value "top" -objects $obj +set_property -name "top_auto_set" -value "0" -objects $obj + +# Set 'sources_1' fileset object +set obj [get_filesets sources_1] +# Add local files from the original project (-no_copy_sources specified) +set files [list \ + [file normalize "${orig_proj_dir}/mig_dram_0/mig_dram_0.xci" ]\ +] +set added_files [add_files -fileset sources_1 $files] + +# Set 'sources_1' fileset file properties for remote files +# None + +# Set 'sources_1' fileset file properties for local files +set file "arty-a7/mig_dram_0/mig_dram_0.xci" +set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] +set_property -name "generate_files_for_reference" -value "0" -objects $file_obj +set_property -name "registered_with_manager" -value "1" -objects $file_obj +if { ![get_property "is_locked" $file_obj] } { + set_property -name "synth_checkpoint_mode" -value "Singular" -objects $file_obj +} +set_property -name "used_in" -value "synthesis implementation" -objects $file_obj +set_property -name "used_in_simulation" -value "0" -objects $file_obj + + +# Create 'constrs_1' fileset (if not found) +if {[string equal [get_filesets -quiet constrs_1] ""]} { + create_fileset -constrset constrs_1 +} + +# Set 'constrs_1' fileset object +set obj [get_filesets constrs_1] + +# Add/Import constrs file and set constrs file properties +set file "[file normalize ${origin_dir}/arty-a7/Arty-A7-35-Master.xdc]" +set file_added [add_files -norecurse -fileset $obj [list $file]] +set file "$origin_dir/arty-a7/Arty-A7-35-Master.xdc" +set file [file normalize $file] +set file_obj [get_files -of_objects [get_filesets constrs_1] [list "*$file"]] +set_property -name "file_type" -value "XDC" -objects $file_obj + +# Set 'constrs_1' fileset properties +set obj [get_filesets constrs_1] +set_property -name "target_constrs_file" -value "$orig_proj_dir/Arty-A7-35-Master.xdc" -objects $obj +set_property -name "target_ucf" -value "$orig_proj_dir/Arty-A7-35-Master.xdc" -objects $obj + +# Create 'sim_1' fileset (if not found) +if {[string equal [get_filesets -quiet sim_1] ""]} { + create_fileset -simset sim_1 +} + +# Set 'sim_1' fileset object +set obj [get_filesets sim_1] +# Add local files from the original project (-no_copy_sources specified) +set files [list \ + [file normalize "${origin_dir}/src/uart_tb.v" ]\ + [file normalize "${orig_proj_dir}/testbench_behav1.wcfg" ]\ +] +set added_files [add_files -fileset sim_1 $files] + +# Set 'sim_1' fileset file properties for remote files +# None + +# Set 'sim_1' fileset file properties for local files +set file [file normalize "${origin_dir}/src/uart_tb.v"] +set file_obj [get_files -of_objects [get_filesets sim_1] [list "*$file"]] +set_property -name "used_in" -value "" -objects $file_obj +set_property -name "used_in_implementation" -value "0" -objects $file_obj +set_property -name "used_in_simulation" -value "0" -objects $file_obj +set_property -name "used_in_synthesis" -value "0" -objects $file_obj + + +# Set 'sim_1' fileset properties +set obj [get_filesets sim_1] +set_property -name "hbs.configure_design_for_hier_access" -value "1" -objects $obj +set_property -name "nl.mode" -value "funcsim" -objects $obj +set_property -name "top" -value "testbench" -objects $obj +set_property -name "top_lib" -value "xil_defaultlib" -objects $obj + +# Create 'sim_fifo' fileset (if not found) +if {[string equal [get_filesets -quiet sim_fifo] ""]} { + create_fileset -simset sim_fifo +} + +# Set 'sim_fifo' fileset object +set obj [get_filesets sim_fifo] +# Add local files from the original project (-no_copy_sources specified) +set files [list \ + [file normalize "${origin_dir}/src/fifo.v" ]\ + [file normalize "${origin_dir}/src/fifo_testbench.v" ]\ +] +set added_files [add_files -fileset sim_fifo $files] + +# Set 'sim_fifo' fileset file properties for remote files +# None + +# Set 'sim_fifo' fileset file properties for local files +# None + +# Set 'sim_fifo' fileset properties +set obj [get_filesets sim_fifo] +set_property -name "hbs.configure_design_for_hier_access" -value "1" -objects $obj +set_property -name "top" -value "fifo_testbench" -objects $obj +set_property -name "top_auto_set" -value "0" -objects $obj + +# Create 'sim_sdspi' fileset (if not found) +if {[string equal [get_filesets -quiet sim_sdspi] ""]} { + create_fileset -simset sim_sdspi +} + +# Set 'sim_sdspi' fileset object +set obj [get_filesets sim_sdspi] +# Add local files from the original project (-no_copy_sources specified) +set files [list \ + [file normalize "${orig_proj_dir}/sdspi_testbench_behav.wcfg" ]\ +] +set added_files [add_files -fileset sim_sdspi $files] + +# Set 'sim_sdspi' fileset file properties for remote files +# None + +# Set 'sim_sdspi' fileset file properties for local files +# None + +# Set 'sim_sdspi' fileset properties +set obj [get_filesets sim_sdspi] +set_property -name "hbs.configure_design_for_hier_access" -value "1" -objects $obj +set_property -name "sim_mode" -value "post-synthesis" -objects $obj +set_property -name "top" -value "sdspi_testbench" -objects $obj +set_property -name "top_auto_set" -value "0" -objects $obj +set_property -name "top_lib" -value "xil_defaultlib" -objects $obj +set_property -name "xsim.simulate.runtime" -value "10ms" -objects $obj + +# Set 'utils_1' fileset object +set obj [get_filesets utils_1] +# Empty (no sources present) + +# Set 'utils_1' fileset properties +set obj [get_filesets utils_1] + +# Create 'synth_1' run (if not found) +if {[string equal [get_runs -quiet synth_1] ""]} { + create_run -name synth_1 -part xc7a35ticsg324-1L -flow {Vivado Synthesis 2020} -strategy "Vivado Synthesis Defaults" -report_strategy {No Reports} -constrset constrs_1 +} else { + set_property strategy "Vivado Synthesis Defaults" [get_runs synth_1] + set_property flow "Vivado Synthesis 2020" [get_runs synth_1] +} +set obj [get_runs synth_1] +set_property set_report_strategy_name 1 $obj +set_property report_strategy {Vivado Synthesis Default Reports} $obj +set_property set_report_strategy_name 0 $obj +# Create 'synth_1_synth_report_utilization_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs synth_1] synth_1_synth_report_utilization_0] "" ] } { + create_report_config -report_name synth_1_synth_report_utilization_0 -report_type report_utilization:1.0 -steps synth_design -runs synth_1 +} +set obj [get_report_configs -of_objects [get_runs synth_1] synth_1_synth_report_utilization_0] +if { $obj != "" } { + +} +set obj [get_runs synth_1] +set_property -name "needs_refresh" -value "1" -objects $obj +set_property -name "strategy" -value "Vivado Synthesis Defaults" -objects $obj + +# set the current synth run +current_run -synthesis [get_runs synth_1] + +# Create 'impl_1' run (if not found) +if {[string equal [get_runs -quiet impl_1] ""]} { + create_run -name impl_1 -part xc7a35ticsg324-1L -flow {Vivado Implementation 2020} -strategy "Performance_RefinePlacement" -report_strategy {No Reports} -constrset constrs_1 -parent_run synth_1 +} else { + set_property strategy "Performance_RefinePlacement" [get_runs impl_1] + set_property flow "Vivado Implementation 2020" [get_runs impl_1] +} +set obj [get_runs impl_1] +set_property set_report_strategy_name 1 $obj +set_property report_strategy {Vivado Implementation Default Reports} $obj +set_property set_report_strategy_name 0 $obj +# Create 'impl_1_init_report_timing_summary_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_init_report_timing_summary_0] "" ] } { + create_report_config -report_name impl_1_init_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps init_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_init_report_timing_summary_0] +if { $obj != "" } { +set_property -name "is_enabled" -value "0" -objects $obj +set_property -name "options.max_paths" -value "10" -objects $obj + +} +# Create 'impl_1_opt_report_drc_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_opt_report_drc_0] "" ] } { + create_report_config -report_name impl_1_opt_report_drc_0 -report_type report_drc:1.0 -steps opt_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_opt_report_drc_0] +if { $obj != "" } { + +} +# Create 'impl_1_opt_report_timing_summary_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_opt_report_timing_summary_0] "" ] } { + create_report_config -report_name impl_1_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps opt_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_opt_report_timing_summary_0] +if { $obj != "" } { +set_property -name "is_enabled" -value "0" -objects $obj +set_property -name "options.max_paths" -value "10" -objects $obj + +} +# Create 'impl_1_power_opt_report_timing_summary_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_power_opt_report_timing_summary_0] "" ] } { + create_report_config -report_name impl_1_power_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps power_opt_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_power_opt_report_timing_summary_0] +if { $obj != "" } { +set_property -name "is_enabled" -value "0" -objects $obj +set_property -name "options.max_paths" -value "10" -objects $obj + +} +# Create 'impl_1_place_report_io_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_io_0] "" ] } { + create_report_config -report_name impl_1_place_report_io_0 -report_type report_io:1.0 -steps place_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_io_0] +if { $obj != "" } { + +} +# Create 'impl_1_place_report_utilization_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_utilization_0] "" ] } { + create_report_config -report_name impl_1_place_report_utilization_0 -report_type report_utilization:1.0 -steps place_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_utilization_0] +if { $obj != "" } { + +} +# Create 'impl_1_place_report_control_sets_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_control_sets_0] "" ] } { + create_report_config -report_name impl_1_place_report_control_sets_0 -report_type report_control_sets:1.0 -steps place_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_control_sets_0] +if { $obj != "" } { +set_property -name "options.verbose" -value "1" -objects $obj + +} +# Create 'impl_1_place_report_incremental_reuse_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_incremental_reuse_0] "" ] } { + create_report_config -report_name impl_1_place_report_incremental_reuse_0 -report_type report_incremental_reuse:1.0 -steps place_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_incremental_reuse_0] +if { $obj != "" } { +set_property -name "is_enabled" -value "0" -objects $obj + +} +# Create 'impl_1_place_report_incremental_reuse_1' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_incremental_reuse_1] "" ] } { + create_report_config -report_name impl_1_place_report_incremental_reuse_1 -report_type report_incremental_reuse:1.0 -steps place_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_incremental_reuse_1] +if { $obj != "" } { +set_property -name "is_enabled" -value "0" -objects $obj + +} +# Create 'impl_1_place_report_timing_summary_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_timing_summary_0] "" ] } { + create_report_config -report_name impl_1_place_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps place_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_place_report_timing_summary_0] +if { $obj != "" } { +set_property -name "is_enabled" -value "0" -objects $obj +set_property -name "options.max_paths" -value "10" -objects $obj + +} +# Create 'impl_1_post_place_power_opt_report_timing_summary_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_post_place_power_opt_report_timing_summary_0] "" ] } { + create_report_config -report_name impl_1_post_place_power_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps post_place_power_opt_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_post_place_power_opt_report_timing_summary_0] +if { $obj != "" } { +set_property -name "is_enabled" -value "0" -objects $obj +set_property -name "options.max_paths" -value "10" -objects $obj + +} +# Create 'impl_1_phys_opt_report_timing_summary_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_phys_opt_report_timing_summary_0] "" ] } { + create_report_config -report_name impl_1_phys_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps phys_opt_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_phys_opt_report_timing_summary_0] +if { $obj != "" } { +set_property -name "is_enabled" -value "0" -objects $obj +set_property -name "options.max_paths" -value "10" -objects $obj + +} +# Create 'impl_1_route_report_drc_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_drc_0] "" ] } { + create_report_config -report_name impl_1_route_report_drc_0 -report_type report_drc:1.0 -steps route_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_drc_0] +if { $obj != "" } { + +} +# Create 'impl_1_route_report_methodology_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_methodology_0] "" ] } { + create_report_config -report_name impl_1_route_report_methodology_0 -report_type report_methodology:1.0 -steps route_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_methodology_0] +if { $obj != "" } { + +} +# Create 'impl_1_route_report_power_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_power_0] "" ] } { + create_report_config -report_name impl_1_route_report_power_0 -report_type report_power:1.0 -steps route_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_power_0] +if { $obj != "" } { + +} +# Create 'impl_1_route_report_route_status_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_route_status_0] "" ] } { + create_report_config -report_name impl_1_route_report_route_status_0 -report_type report_route_status:1.0 -steps route_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_route_status_0] +if { $obj != "" } { + +} +# Create 'impl_1_route_report_timing_summary_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_timing_summary_0] "" ] } { + create_report_config -report_name impl_1_route_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps route_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_timing_summary_0] +if { $obj != "" } { +set_property -name "options.max_paths" -value "10" -objects $obj + +} +# Create 'impl_1_route_report_incremental_reuse_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_incremental_reuse_0] "" ] } { + create_report_config -report_name impl_1_route_report_incremental_reuse_0 -report_type report_incremental_reuse:1.0 -steps route_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_incremental_reuse_0] +if { $obj != "" } { + +} +# Create 'impl_1_route_report_clock_utilization_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_clock_utilization_0] "" ] } { + create_report_config -report_name impl_1_route_report_clock_utilization_0 -report_type report_clock_utilization:1.0 -steps route_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_clock_utilization_0] +if { $obj != "" } { + +} +# Create 'impl_1_route_report_bus_skew_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_bus_skew_0] "" ] } { + create_report_config -report_name impl_1_route_report_bus_skew_0 -report_type report_bus_skew:1.1 -steps route_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_route_report_bus_skew_0] +if { $obj != "" } { +set_property -name "options.warn_on_violation" -value "1" -objects $obj + +} +# Create 'impl_1_post_route_phys_opt_report_timing_summary_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_post_route_phys_opt_report_timing_summary_0] "" ] } { + create_report_config -report_name impl_1_post_route_phys_opt_report_timing_summary_0 -report_type report_timing_summary:1.0 -steps post_route_phys_opt_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_post_route_phys_opt_report_timing_summary_0] +if { $obj != "" } { +set_property -name "options.max_paths" -value "10" -objects $obj +set_property -name "options.warn_on_violation" -value "1" -objects $obj + +} +# Create 'impl_1_post_route_phys_opt_report_bus_skew_0' report (if not found) +if { [ string equal [get_report_configs -of_objects [get_runs impl_1] impl_1_post_route_phys_opt_report_bus_skew_0] "" ] } { + create_report_config -report_name impl_1_post_route_phys_opt_report_bus_skew_0 -report_type report_bus_skew:1.1 -steps post_route_phys_opt_design -runs impl_1 +} +set obj [get_report_configs -of_objects [get_runs impl_1] impl_1_post_route_phys_opt_report_bus_skew_0] +if { $obj != "" } { +set_property -name "options.warn_on_violation" -value "1" -objects $obj + +} +set obj [get_runs impl_1] +set_property -name "needs_refresh" -value "1" -objects $obj +set_property -name "strategy" -value "Performance_RefinePlacement" -objects $obj +set_property -name "steps.place_design.args.directive" -value "ExtraPostPlacementOpt" -objects $obj +set_property -name "steps.phys_opt_design.args.directive" -value "Explore" -objects $obj +set_property -name "steps.route_design.args.directive" -value "Explore" -objects $obj +set_property -name "steps.write_bitstream.args.bin_file" -value "1" -objects $obj +set_property -name "steps.write_bitstream.args.readback_file" -value "0" -objects $obj +set_property -name "steps.write_bitstream.args.verbose" -value "0" -objects $obj + +# set the current impl run +current_run -implementation [get_runs impl_1] + +puts "INFO: Project created:${_xil_proj_name_}" +# Create 'drc_1' gadget (if not found) +if {[string equal [get_dashboard_gadgets [ list "drc_1" ] ] ""]} { +create_dashboard_gadget -name {drc_1} -type drc +} +set obj [get_dashboard_gadgets [ list "drc_1" ] ] +set_property -name "reports" -value "impl_1#impl_1_route_report_drc_0" -objects $obj + +# Create 'methodology_1' gadget (if not found) +if {[string equal [get_dashboard_gadgets [ list "methodology_1" ] ] ""]} { +create_dashboard_gadget -name {methodology_1} -type methodology +} +set obj [get_dashboard_gadgets [ list "methodology_1" ] ] +set_property -name "reports" -value "impl_1#impl_1_route_report_methodology_0" -objects $obj + +# Create 'power_1' gadget (if not found) +if {[string equal [get_dashboard_gadgets [ list "power_1" ] ] ""]} { +create_dashboard_gadget -name {power_1} -type power +} +set obj [get_dashboard_gadgets [ list "power_1" ] ] +set_property -name "reports" -value "impl_1#impl_1_route_report_power_0" -objects $obj + +# Create 'timing_1' gadget (if not found) +if {[string equal [get_dashboard_gadgets [ list "timing_1" ] ] ""]} { +create_dashboard_gadget -name {timing_1} -type timing +} +set obj [get_dashboard_gadgets [ list "timing_1" ] ] +set_property -name "reports" -value "impl_1#impl_1_route_report_timing_summary_0" -objects $obj + +# Create 'utilization_1' gadget (if not found) +if {[string equal [get_dashboard_gadgets [ list "utilization_1" ] ] ""]} { +create_dashboard_gadget -name {utilization_1} -type utilization +} +set obj [get_dashboard_gadgets [ list "utilization_1" ] ] +set_property -name "reports" -value "synth_1#synth_1_synth_report_utilization_0" -objects $obj +set_property -name "run.step" -value "synth_design" -objects $obj +set_property -name "run.type" -value "synthesis" -objects $obj + +# Create 'utilization_2' gadget (if not found) +if {[string equal [get_dashboard_gadgets [ list "utilization_2" ] ] ""]} { +create_dashboard_gadget -name {utilization_2} -type utilization +} +set obj [get_dashboard_gadgets [ list "utilization_2" ] ] +set_property -name "reports" -value "impl_1#impl_1_place_report_utilization_0" -objects $obj + +move_dashboard_gadget -name {utilization_1} -row 0 -col 0 +move_dashboard_gadget -name {power_1} -row 1 -col 0 +move_dashboard_gadget -name {drc_1} -row 2 -col 0 +move_dashboard_gadget -name {timing_1} -row 0 -col 1 +move_dashboard_gadget -name {utilization_2} -row 1 -col 1 +move_dashboard_gadget -name {methodology_1} -row 2 -col 1 diff --git a/rtl/src/bram_tdp.v b/rtl/src/bram_tdp.v new file mode 100644 index 0000000..9537b9c --- /dev/null +++ b/rtl/src/bram_tdp.v @@ -0,0 +1,46 @@ +`timescale 1ns / 1ps +// taken from https://danstrother.com/2010/09/11/inferring-rams-in-fpgas/ +// modified for one read/write-port and one read-only-port, +/// A parameterized, inferable, true dual-port, dual-clock block RAM in Verilog. + +module bram_tdp #( + parameter DATA = 72, + parameter ADDR = 10 +) ( + // Port A + input wire a_clk, + input wire a_rd, + input wire a_wr, + input wire [ADDR-1:0] a_addr, + input wire [DATA-1:0] a_din, + output reg [DATA-1:0] a_dout, + // Port B + input wire b_clk, + input wire [ADDR-1:0] b_addr, + output reg [DATA-1:0] b_dout, + input wire b_rd +); + +// Shared memory + reg [DATA-1:0] mem [(2**ADDR)-1:0]; + + wire a_en = a_rd || a_wr; + +// Port A +always @(posedge a_clk) begin + if(a_en) + begin + if(a_wr) + mem[a_addr] <= a_din; + else if(a_rd) + a_dout <= mem[a_addr]; + end +end + +// Port B +always @(posedge b_clk) begin + if(b_rd) + b_dout <= mem[b_addr]; +end + +endmodule diff --git a/rtl/src/cpuclk.v b/rtl/src/cpuclk.v new file mode 100644 index 0000000..613d85e --- /dev/null +++ b/rtl/src/cpuclk.v @@ -0,0 +1,83 @@ +`timescale 1ns / 1ps + +module cpu_clkgen( + input wire rst, + input wire clk100, + output wire cpuclk, + output wire dram_refclk, + output wire pixclk, + output wire locked + ); + + wire cpuclk_pre, clk_fb, refclk_pre, pixclk_pre; + + MMCME2_BASE #( + .BANDWIDTH("OPTIMIZED"), // Jitter programming (OPTIMIZED, HIGH, LOW) + .CLKFBOUT_MULT_F(10.0), // Multiply value for all CLKOUT (2.000-64.000). + .CLKFBOUT_PHASE(0.0), // Phase offset in degrees of CLKFB (-360.000-360.000). + .CLKIN1_PERIOD(10.0), // Input clock period in ns to ps resolution (i.e. 33.333 is 30 MHz). + // CLKOUT0_DIVIDE - CLKOUT6_DIVIDE: Divide amount for each CLKOUT (1-128) + .CLKOUT0_DIVIDE_F(12.0), // Divide amount for CLKOUT0 (1.000-128.000). + .CLKOUT1_DIVIDE(5), + .CLKOUT2_DIVIDE(40), // 40 = 25MHz pixel clock (should be 25.175MHz per spec) for 640x480 + //.CLKOUT2_DIVIDE(25), // 25 = 40MHz pixel clock for 800x600 + //.CLKOUT2_DIVIDE(15), // 15 = 66.66MHz pixel clock (should be 65.0Mhz per spec) for 1024x768 + .CLKOUT3_DIVIDE(1), + .CLKOUT4_DIVIDE(1), + .CLKOUT5_DIVIDE(1), + .CLKOUT6_DIVIDE(1), + // CLKOUT0_DUTY_CYCLE - CLKOUT6_DUTY_CYCLE: Duty cycle for each CLKOUT (0.01-0.99). + .CLKOUT0_DUTY_CYCLE(0.5), + .CLKOUT1_DUTY_CYCLE(0.5), + .CLKOUT2_DUTY_CYCLE(0.5), + .CLKOUT3_DUTY_CYCLE(0.5), + .CLKOUT4_DUTY_CYCLE(0.5), + .CLKOUT5_DUTY_CYCLE(0.5), + .CLKOUT6_DUTY_CYCLE(0.5), + // CLKOUT0_PHASE - CLKOUT6_PHASE: Phase offset for each CLKOUT (-360.000-360.000). + .CLKOUT0_PHASE(0.0), + .CLKOUT1_PHASE(0.0), + .CLKOUT2_PHASE(0.0), + .CLKOUT3_PHASE(0.0), + .CLKOUT4_PHASE(0.0), + .CLKOUT5_PHASE(0.0), + .CLKOUT6_PHASE(0.0), + .CLKOUT4_CASCADE("FALSE"), // Cascade CLKOUT4 counter with CLKOUT6 (FALSE, TRUE) + .DIVCLK_DIVIDE(1), // Master division value (1-106) + .REF_JITTER1(0.010), // Reference input jitter in UI (0.000-0.999). + .STARTUP_WAIT("FALSE") // Delays DONE until MMCM is locked (FALSE, TRUE) + ) + + MMCME2_BASE_inst ( + /* verilator lint_off PINCONNECTEMPTY */ + // Clock Outputs: 1-bit (each) output: User configurable clock outputs + .CLKOUT0(cpuclk_pre), // 1-bit output: CLKOUT0 + .CLKOUT0B(), // 1-bit output: Inverted CLKOUT0 + .CLKOUT1(refclk_pre), // 1-bit output: CLKOUT1 + .CLKOUT1B(), // 1-bit output: Inverted CLKOUT1 + .CLKOUT2(pixclk_pre), // 1-bit output: CLKOUT2 + .CLKOUT2B(), // 1-bit output: Inverted CLKOUT2 + .CLKOUT3(), // 1-bit output: CLKOUT3 + .CLKOUT3B(), // 1-bit output: Inverted CLKOUT3 + .CLKOUT4(), // 1-bit output: CLKOUT4 + .CLKOUT5(), // 1-bit output: CLKOUT5 + .CLKOUT6(), // 1-bit output: CLKOUT6 + // Feedback Clocks: 1-bit (each) output: Clock feedback ports + .CLKFBOUT(clk_fb), // 1-bit output: Feedback clock + .CLKFBOUTB(), // 1-bit output: Inverted CLKFBOUT + // Status Ports: 1-bit (each) output: MMCM status ports + .LOCKED(locked), // 1-bit output: LOCK + // Clock Inputs: 1-bit (each) input: Clock input + .CLKIN1(clk100), // 1-bit input: Clock + // Control Ports: 1-bit (each) input: MMCM control ports + .PWRDWN(), // 1-bit input: Power-down + /* verilator lint_on PINCONNECTEMPTY */ + .RST(rst), // 1-bit input: Reset + // Feedback Clocks: 1-bit (each) input: Clock feedback ports + .CLKFBIN(clk_fb) // 1-bit input: Feedback clock + ); + + BUFG bufg_cpuclk(.I(cpuclk_pre), .O(cpuclk)); + BUFG bufg_refclk(.I(refclk_pre), .O(dram_refclk)); + BUFG bufg_pixclk(.I(pixclk_pre), .O(pixclk)); +endmodule diff --git a/rtl/src/display_clock.v b/rtl/src/display_clock.v new file mode 100644 index 0000000..898ef7a --- /dev/null +++ b/rtl/src/display_clock.v @@ -0,0 +1,96 @@ +`timescale 1ns / 1ps +`default_nettype none + +// Project F: Display Clocks +// (C)2019 Will Green, Open source hardware released under the MIT License +// Learn more at https://projectf.io + +// Defaults to 25.2 and 126 MHz for 640x480 at 60 Hz + +module display_clock #( + MULT_MASTER=31.5, // master clock multiplier (2.000-64.000) + DIV_MASTER=5, // master clock divider (1-106) + DIV_5X=5.0, // 5x clock divider (1-128) + DIV_1X=25, // 1x clock divider (1-128) + IN_PERIOD=10.0 // period of i_clk in ns (100 MHz = 10.0 ns) + ) + ( + input wire i_clk, // input clock + input wire i_rst, // reset (active high) + output wire o_clk_1x, // pixel clock + output wire o_clk_5x, // 5x clock for 10:1 DDR SerDes + output wire o_locked // clock locked? (active high) + ); + + wire clk_fb; // internal clock feedback + wire clk_1x_pre; + wire clk_5x_pre; + + MMCME2_BASE #( + .BANDWIDTH("OPTIMIZED"), // Jitter programming (OPTIMIZED, HIGH, LOW) + .CLKFBOUT_MULT_F(MULT_MASTER), // Multiply value for all CLKOUT (2.000-64.000). + .CLKFBOUT_PHASE(0.0), // Phase offset in degrees of CLKFB (-360.000-360.000). + .CLKIN1_PERIOD(IN_PERIOD), // Input clock period in ns to ps resolution (i.e. 33.333 is 30 MHz). + // CLKOUT0_DIVIDE - CLKOUT6_DIVIDE: Divide amount for each CLKOUT (1-128) + .CLKOUT0_DIVIDE_F(DIV_5X), // Divide amount for CLKOUT0 (1.000-128.000). + .CLKOUT1_DIVIDE(DIV_1X), + .CLKOUT2_DIVIDE(1), + .CLKOUT3_DIVIDE(1), + .CLKOUT4_DIVIDE(1), + .CLKOUT5_DIVIDE(1), + .CLKOUT6_DIVIDE(1), + // CLKOUT0_DUTY_CYCLE - CLKOUT6_DUTY_CYCLE: Duty cycle for each CLKOUT (0.01-0.99). + .CLKOUT0_DUTY_CYCLE(0.5), + .CLKOUT1_DUTY_CYCLE(0.5), + .CLKOUT2_DUTY_CYCLE(0.5), + .CLKOUT3_DUTY_CYCLE(0.5), + .CLKOUT4_DUTY_CYCLE(0.5), + .CLKOUT5_DUTY_CYCLE(0.5), + .CLKOUT6_DUTY_CYCLE(0.5), + // CLKOUT0_PHASE - CLKOUT6_PHASE: Phase offset for each CLKOUT (-360.000-360.000). + .CLKOUT0_PHASE(0.0), + .CLKOUT1_PHASE(0.0), + .CLKOUT2_PHASE(0.0), + .CLKOUT3_PHASE(0.0), + .CLKOUT4_PHASE(0.0), + .CLKOUT5_PHASE(0.0), + .CLKOUT6_PHASE(0.0), + .CLKOUT4_CASCADE("FALSE"), // Cascade CLKOUT4 counter with CLKOUT6 (FALSE, TRUE) + .DIVCLK_DIVIDE(DIV_MASTER), // Master division value (1-106) + .REF_JITTER1(0.010), // Reference input jitter in UI (0.000-0.999). + .STARTUP_WAIT("FALSE") // Delays DONE until MMCM is locked (FALSE, TRUE) + ) + MMCME2_BASE_inst ( + /* verilator lint_off PINCONNECTEMPTY */ + // Clock Outputs: 1-bit (each) output: User configurable clock outputs + .CLKOUT0(clk_5x_pre), // 1-bit output: CLKOUT0 + .CLKOUT0B(), // 1-bit output: Inverted CLKOUT0 + .CLKOUT1(clk_1x_pre), // 1-bit output: CLKOUT1 + .CLKOUT1B(), // 1-bit output: Inverted CLKOUT1 + .CLKOUT2(), // 1-bit output: CLKOUT2 + .CLKOUT2B(), // 1-bit output: Inverted CLKOUT2 + .CLKOUT3(), // 1-bit output: CLKOUT3 + .CLKOUT3B(), // 1-bit output: Inverted CLKOUT3 + .CLKOUT4(), // 1-bit output: CLKOUT4 + .CLKOUT5(), // 1-bit output: CLKOUT5 + .CLKOUT6(), // 1-bit output: CLKOUT6 + // Feedback Clocks: 1-bit (each) output: Clock feedback ports + .CLKFBOUT(clk_fb), // 1-bit output: Feedback clock + .CLKFBOUTB(), // 1-bit output: Inverted CLKFBOUT + // Status Ports: 1-bit (each) output: MMCM status ports + .LOCKED(o_locked), // 1-bit output: LOCK + // Clock Inputs: 1-bit (each) input: Clock input + .CLKIN1(i_clk), // 1-bit input: Clock + // Control Ports: 1-bit (each) input: MMCM control ports + .PWRDWN(), // 1-bit input: Power-down + /* verilator lint_on PINCONNECTEMPTY */ + .RST(i_rst), // 1-bit input: Reset + // Feedback Clocks: 1-bit (each) input: Clock feedback ports + .CLKFBIN(clk_fb) // 1-bit input: Feedback clock + ); + + // explicitly buffer output clocks + BUFG bufg_clk_pix(.I(clk_1x_pre), .O(o_clk_1x)); + BUFG bufg_clk_pix_5x(.I(clk_5x_pre), .O(o_clk_5x)); + +endmodule \ No newline at end of file diff --git a/rtl/src/dram_bridge.v b/rtl/src/dram_bridge.v new file mode 100644 index 0000000..102a8cf --- /dev/null +++ b/rtl/src/dram_bridge.v @@ -0,0 +1,165 @@ +`timescale 1ns / 1ps + +module dram_bridge #(ADDR_WIDTH = 32, WIDTH = 32) +( + // local bus + input wire [ADDR_WIDTH-1:0] mem_addr, + output wire [WIDTH-1:0] mem_read_data, + input wire [WIDTH-1:0] mem_write_data, + input wire mem_read_enable, + input wire mem_write_enable, + output wire mem_wait, + + input wire rst_n, + input wire dram_front_clk, + input wire dram_refclk, + + // DDR3 SDRAM + inout wire [15:0] ddr3_dq, + inout wire [1:0] ddr3_dqs_n, + inout wire [1:0] ddr3_dqs_p, + + output wire [13:0] ddr3_addr, + output wire [2:0] ddr3_ba, + output wire ddr3_ras_n, + output wire ddr3_cas_n, + output wire ddr3_we_n, + output wire ddr3_reset_n, + output wire [0:0] ddr3_ck_p, + output wire [0:0] ddr3_ck_n, + output wire [0:0] ddr3_cke, + output wire [0:0] ddr3_cs_n, + output wire [1:0] ddr3_dm, + output wire [0:0] ddr3_odt +); + + localparam DRAM_ADDR_WIDTH = 28, DRAM_DATA_WIDTH = 128, DRAM_MASK_WIDTH = 16; + wire [DRAM_ADDR_WIDTH-1:0] app_addr; + wire [2:0] app_cmd; + wire app_en; + wire app_rdy; + wire [DRAM_DATA_WIDTH-1:0] app_rd_data; + wire app_rd_data_end; + wire app_rd_data_valid; + wire [DRAM_DATA_WIDTH-1:0] app_wdf_data; + wire app_wdf_end; + wire [DRAM_MASK_WIDTH-1:0] app_wdf_mask; + wire app_wdf_rdy; + wire app_sr_active; + wire app_ref_ack; + wire app_zq_ack; + wire app_wdf_wren; + wire [11:0] device_temp; + wire ui_clk, ui_rst_sync; + wire init_calib_complete; + + localparam CMD_READ = 3'b1; + localparam CMD_WRITE = 3'b0; + + mig_dram_0 dram0( + // Inouts + .ddr3_dq(ddr3_dq), + .ddr3_dqs_n(ddr3_dqs_n), + .ddr3_dqs_p(ddr3_dqs_p), + // Outputs + .ddr3_addr(ddr3_addr), + .ddr3_ba(ddr3_ba), + .ddr3_ras_n(ddr3_ras_n), + .ddr3_cas_n(ddr3_cas_n), + .ddr3_we_n(ddr3_we_n), + .ddr3_reset_n(ddr3_reset_n), + .ddr3_ck_p(ddr3_ck_p), + .ddr3_ck_n(ddr3_ck_n), + .ddr3_cke(ddr3_cke), + .ddr3_cs_n(ddr3_cs_n), + .ddr3_dm(ddr3_dm), + .ddr3_odt(ddr3_odt), +// Application interface ports + .app_addr (app_addr), + .app_cmd (app_cmd), + .app_en (app_en), + .app_wdf_data (app_wdf_data), + .app_wdf_mask (app_wdf_mask), + .app_wdf_end (app_wdf_end), + .app_wdf_wren (app_wdf_wren), + .app_rd_data (app_rd_data), + .app_rd_data_end (app_rd_data_end), + .app_rd_data_valid (app_rd_data_valid), + .app_rdy (app_rdy), + .app_wdf_rdy (app_wdf_rdy), + .app_sr_req (1'b0), + .app_ref_req (1'b0), + .app_zq_req (1'b0), + .app_sr_active (app_sr_active), + .app_ref_ack (app_ref_ack), + .app_zq_ack (app_zq_ack), + .ui_clk (ui_clk), + .ui_clk_sync_rst (ui_rst_sync), + +// System Clock Ports + .sys_clk_i (dram_front_clk), +// Reference Clock Ports + .clk_ref_i (dram_refclk), + .device_temp (device_temp), + .init_calib_complete (init_calib_complete), + .sys_rst (rst_n) + ); + +// reg [DRAM_DATA_WIDTH-1:0] read_cache; +// reg [ADDR_WIDTH-1:0] cached_addr; +// wire cache_hit = cached_addr == mem_addr; +// wire [DRAM_DATA_WIDTH-1:0] read_data_wrapper = cache_hit ? read_cache : app_rd_data; + + reg [WIDTH-1:0] read_buf; + reg read_inprogress = 0; + + assign app_rd_data_end = 1'b1; + //assign app_wdf_mask = 16'b1111111111111100; + + // addresses on the memory interface are aligned to 16 bytes + // and 28 bits wide (=256MB) + assign app_addr = { mem_addr[DRAM_ADDR_WIDTH:4], 4'b0000 }; + //assign app_addr = { 28'b0 }; + + // select a word from the 128 bits transferred by the dram controller + // according to the lower bits of the address (ignoring bits 1:0) + wire [WIDTH-1:0] read_word; + wire [1:0] word_sel = mem_addr[3:2]; + + assign read_word = word_sel == 3'b11 ? app_rd_data[31:0] : + word_sel == 3'b10 ? app_rd_data[63:32] : + word_sel == 3'b01 ? app_rd_data[95:64] : + app_rd_data[127:96]; + + assign mem_read_data = app_rd_data_valid ? read_word : read_buf; + + // set the write mask according to the lower bits of the address + // (ignoring bit 0) + assign app_wdf_mask = word_sel == 3'b11 ? 16'b1111111111110000 : + word_sel == 3'b10 ? 16'b1111111100001111 : + word_sel == 3'b01 ? 16'b1111000011111111 : + 16'b0000111111111111 ; + + wire write_ready = mem_write_enable & app_wdf_rdy & app_rdy; + assign app_wdf_wren = mem_write_enable & write_ready; + assign app_wdf_end = mem_write_enable & write_ready; + assign app_wdf_data = { {4{mem_write_data}} }; + + assign mem_wait = (mem_read_enable & ~read_inprogress) | + (mem_write_enable & (~app_wdf_rdy | ~app_rdy)) | + (read_inprogress & ~app_rd_data_valid); + + assign app_en = (mem_read_enable & ~read_inprogress) | + (mem_write_enable & write_ready); + assign app_cmd = mem_read_enable ? CMD_READ : CMD_WRITE; + + always @(posedge dram_front_clk) + begin + if(mem_read_enable & ~read_inprogress & app_rdy) + read_inprogress <= 1; + if(read_inprogress & app_rd_data_valid) + read_inprogress <= 0; + if(mem_read_enable & app_rd_data_valid) + read_buf <= mem_read_data; + end +endmodule diff --git a/rtl/src/fifo.v b/rtl/src/fifo.v new file mode 100644 index 0000000..16d9583 --- /dev/null +++ b/rtl/src/fifo.v @@ -0,0 +1,53 @@ +`timescale 1ns / 1ps + +// a simple fifo +module fifo #(parameter DATA_WIDTH = 8, ADDR_WIDTH = 4)( + input wire clk, + input wire reset, + input wire wr_en, + input wire rd_en, + input wire [DATA_WIDTH-1:0] wr_data, + output wire [DATA_WIDTH-1:0] rd_data, + output wire wr_full, + output wire rd_empty + ); + + reg [DATA_WIDTH-1:0] mem [0:2**ADDR_WIDTH-1]; + reg [ADDR_WIDTH:0] head_x = 0; // head and tail have one extra bit + reg [ADDR_WIDTH:0] tail_x = 0; // for detecting overflows + wire [ADDR_WIDTH-1:0] head = head_x[ADDR_WIDTH-1:0]; + wire [ADDR_WIDTH-1:0] tail = tail_x[ADDR_WIDTH-1:0]; + + assign rd_data = mem[tail]; + // the fifo is full when head and tail pointer are the same + // and the extra bits differ (a wraparound occured) + assign wr_full = (head == tail) && (head_x[ADDR_WIDTH] != tail_x[ADDR_WIDTH]); + // the fifo is empty when head and tail pointer are the same + // and the extra bits are the same (no wraparound) + assign rd_empty = (head == tail) && (head_x[ADDR_WIDTH] == tail_x[ADDR_WIDTH]); + + // Writing to FIFO + always @(posedge clk) begin + if (reset) + head_x <= 0; + else if (wr_en) + begin + mem[head] <= wr_data; + // move head, possible wraparound + head_x <= head_x + 1'b1; + end + end + + // Reading from FIFO + always @(posedge clk) + begin + if (reset) + tail_x <= 0; + else if (rd_en) + begin + // rd_data always has current tail data + // move tail, possible wraparound + tail_x <= tail_x + 1'b1; + end + end +endmodule \ No newline at end of file diff --git a/rtl/src/fifo_testbench.v b/rtl/src/fifo_testbench.v new file mode 100644 index 0000000..ccc29ee --- /dev/null +++ b/rtl/src/fifo_testbench.v @@ -0,0 +1,116 @@ +`timescale 1ns / 1ns +`default_nettype none + +module fifo_testbench(); + // Test signals + reg clk = 0; + reg reset = 0; + reg wr_en = 0; + reg rd_en = 0; + reg [7:0] wr_data = 0; + wire [7:0] rd_data; + wire wr_full; + wire rd_empty; + + parameter CLOCK_NS = 10; + + // Unit Under Test + fifo #( + .DATA_WIDTH(8), + .ADDR_WIDTH(4) + ) UUT ( + .clk(clk), + .reset(reset), + .wr_en(wr_en), + .rd_en(rd_en), + .rd_data(rd_data), + .wr_data(wr_data), + .wr_full(wr_full), + .rd_empty(rd_empty) + ); + + // testbench clock + always + #(CLOCK_NS/2) clk <= ~clk; + + initial + begin + // issue reset + reset = 1'b1; + #10 + reset = 1'b0; + #10 + + // Write two bytes + wr_data <= 8'hAB; + wr_en <= 1'b1; + #10; + wr_data <= 8'hCD; + wr_en <= 1'b1; + #10; + wr_en <= 1'b0; + #10 + + // read fifo tail + if (rd_data == 8'hAB) + $display("Pass - Byte 1"); + else + $display("Failed - Byte 2"); + + // read/remove byte from tail + rd_en <= 1'b1; + #10 + // check next byte + if (rd_data == 8'hCD) + $display("Pass - Byte 2"); + else + $display("Failed - Byte 2"); + + // remove 2nd byte + rd_en <= 1'b1; + #10 + + rd_en <= 1'b0; + #10 + + // Write until full + rd_en <= 1'b0; + wr_en <= 1'b0; + + for (integer i = 0; i < 16; i = i + 1) begin + wr_data <= i; + wr_en <= 1'b1; + #10; + end + wr_en <= 1'b0; + + if (wr_full) + $display("Pass - Fifo full"); + else + $display("Failed - Fifo full"); + + + // read until empty + rd_en <= 1'b0; + wr_en <= 1'b0; + + for (integer i = 0; i < 16; i = i + 1) begin + rd_en <= 1'b1; + #10; + end + rd_en <= 1'b0; + + if (rd_empty) + $display("Pass - Fifo empty"); + else + $display("Failed - Fifo empty"); + $finish(); + end + + initial + begin + // Required to dump signals + $dumpfile("fifo_tb_dump.vcd"); + $dumpvars(0); + end +endmodule diff --git a/rtl/src/irqctrl.v b/rtl/src/irqctrl.v new file mode 100644 index 0000000..1a079bf --- /dev/null +++ b/rtl/src/irqctrl.v @@ -0,0 +1,73 @@ +`timescale 1ns / 1ps + +module irqctrl #(IRQ_LINES = 2, IRQ_DELAY_WIDTH = 4) ( + input wire clk, + input wire [IRQ_LINES-1:0] irq_in, + input wire cs, + input wire wr_en, + input wire irq_wr_seten, + output wire [IRQ_LINES-1:0] rd_data, + output wire irq_out + ); + + reg [IRQ_LINES-1:0] irq_status; // a 1 bit here means we have seen an interrupt on that line + reg [IRQ_LINES-1:0] irq_mask; // a bit in irq_status is only set if the corresponding bit in irq_mask is not set + // irq_mask is set from irq_status when an interrupt occurs (ie irq_out is set) + + reg irq_enabled; // globally enable/disable irq_out + reg [IRQ_DELAY_WIDTH-1:0] irq_delay; // counter to delay irq_out for a few cycles + reg irq_delaying; // delay is active + + wire irq_pending = (irq_status != 0); + + assign rd_data = irq_mask; + assign irq_out = irq_enabled && irq_pending && !irq_delaying; + + // irq_status and irq_pending flags + always @(posedge clk) + begin + if(irq_out) // when an interrupt is being signaled to the cpu, + irq_status <= 0; // clear irq status, status will be copied to irq_mask (see below) + else + if(irq_in != 0) + irq_status <= irq_status | (irq_in & ~irq_mask); // add active irq to irq_status + end + + // irq mask + always @(posedge clk) + begin + if (cs && wr_en && irq_wr_seten) // when enabling interrupts, clear mask + irq_mask <= 0; + else + if(irq_out) // when signalling an interrupt, set mask from status + irq_mask <= irq_status; + end + + // manage irq_enabled and irq_delay/irq_delaying + always @(posedge clk) + begin + if(cs && wr_en) // when writing to control register + begin + if(irq_wr_seten) // if wr_seten flag is set, enable interrupts and start delay + begin + irq_enabled <= 1; + irq_delaying <= 1; + irq_delay <= 1; + end + else + irq_enabled <= 0; // else disable interrupts + end + else if(irq_out) irq_enabled <= 0; // after sending interrupt to cpu, disable further interrupts + + if(irq_delaying) // the delay gives the CPU a chance to return from an interrupt handler + begin // if an interrupt is triggered again right after re-enabling interrupts + if(irq_delay==0) + begin + irq_delay <= 1; + irq_delaying <= 0; + end + else + irq_delay <= irq_delay + 1; + end + end + endmodule diff --git a/rtl/src/mem.v b/rtl/src/mem.v new file mode 100644 index 0000000..954443a --- /dev/null +++ b/rtl/src/mem.v @@ -0,0 +1,161 @@ +`timescale 1ns / 1ps +////////////////////////////////////////////////////////////////////////////////// +// Company: +// Engineer: +// +// Create Date: 05.01.2021 21:53:41 +// Design Name: +// Module Name: mem +// Project Name: +// Target Devices: +// Tool Versions: +// Description: +// +// Dependencies: +// +// Revision: +// Revision 0.01 - File Created +// Additional Comments: +// +////////////////////////////////////////////////////////////////////////////////// + +// 32 bit wide rom with byte addressing (address bits 1-0 are ignored) +module rom32 #(parameter ADDR_WIDTH = 11, DATA_WIDTH = 32) +( + input wire clk, + input wire [ADDR_WIDTH-1:0] addr, + output reg [DATA_WIDTH-1:0] data_out, + input wire read_enable + ); + + wire [ADDR_WIDTH-2:0] internal_addr = addr[ADDR_WIDTH-1:2]; // -> ignore bit 0 + reg [DATA_WIDTH-1:0] rom [0:(2**(ADDR_WIDTH-2))-1]; + + initial begin + $readmemb("C:\\Users\\sebastian\\develop\\fpga\\vdumbcpu\\rom.mem", rom); + end + + always @(posedge clk) data_out <= rom[internal_addr]; + +endmodule + +module ram32 #(parameter ADDR_WIDTH = 16, DATA_WIDTH = 32) + +( + input wire clk, + input wire [ADDR_WIDTH-1:0] addr, + output reg [DATA_WIDTH-1:0] data_out, + input wire read_enable, + input wire [DATA_WIDTH-1:0] data_in, + input wire write_enable + ); + + reg [DATA_WIDTH-1:0] ram [0:(2**(ADDR_WIDTH-2))-1]; // 32bit words with byte addressing + wire [ADDR_WIDTH-2:0] internal_addr = addr[ADDR_WIDTH-1:2]; // -> ignore bit 1-0 + + always @(posedge clk) + begin + if(read_enable) + data_out <= ram[internal_addr]; + if(write_enable) + ram[internal_addr] <= data_in; + end +endmodule + +module mem #(parameter ADDR_WIDTH = 32, + parameter DATA_WIDTH = 32) +( + input wire clk, rst_n, + input wire [ADDR_WIDTH-1:0] addr, + output wire [DATA_WIDTH-1:0] data_out, + input wire read_enable, + input wire [DATA_WIDTH-1:0] data_in, + input wire write_enable, + output wire io_enable, + input wire [DATA_WIDTH-1:0] io_rd_data, + output wire mem_wait, + + output wire [ADDR_WIDTH-1:0] dram_addr, + input wire [DATA_WIDTH-1:0] dram_read_data, + output wire [DATA_WIDTH-1:0] dram_write_data, + output wire dram_read_enable, + output wire dram_write_enable, + input wire dram_wait + ); + + wire [DATA_WIDTH-1:0] ram_out, rom_out, dram_out; + + // address map: + // ROM $0000 - $07FF 2K + // IO $0800 - $0FFF 2K + // RAM1 $1000 - $FFFF 60K + // RAM2 $10000 - $FFFFFFFF ~4GB + + wire ram_cs = addr[ADDR_WIDTH-1:12] != { {(ADDR_WIDTH-12){1'b0}}}; + wire ram1_cs = ram_cs && (addr[ADDR_WIDTH-1:16] == { {(ADDR_WIDTH-16){1'b0}}}); + wire ram2_cs = ram_cs && !ram1_cs; + wire rom_cs = !ram_cs && addr[11] == 1'b0; + wire io_cs = !ram_cs && addr[11] == 1'b1; + + assign io_enable = io_cs; + + wire ram_read = ram1_cs && read_enable; + wire ram_write = ram1_cs && write_enable; + wire rom_read = rom_cs && read_enable; + + reg [DATA_WIDTH-1:0] data_buf; + + localparam SEL_RAM1 = 0; + localparam SEL_RAM2 = 1; + localparam SEL_ROM = 2; + localparam SEL_IO = 3; + localparam SEL_ERR = 4; + + reg [1:0] out_sel; + + // test + reg [1:0] wait_state; + + ram32 #(.ADDR_WIDTH(16)) ram0 // 64KB RAM + ( + .clk(clk), + .addr(addr[15:0]), + .data_out(ram_out), + .read_enable(ram_read), + .data_in(data_in), + .write_enable(ram_write) + ); + + rom32 #(.ADDR_WIDTH(11)) rom0 // 2KB ROM + ( + .clk(clk), + .addr(addr[10:0]), + .data_out(rom_out), + .read_enable(rom_read) + ); + + assign dram_out = dram_read_data; + assign dram_addr = addr; + assign dram_write_data = data_in; + assign dram_read_enable = ram2_cs & read_enable; + assign dram_write_enable = ram2_cs & write_enable; + + assign data_out = (out_sel == SEL_RAM1 ) ? ram_out : + (out_sel == SEL_RAM2 ) ? dram_out : + (out_sel == SEL_ROM ) ? rom_out : + (out_sel == SEL_IO ) ? io_rd_data : + data_buf; + + assign mem_wait = ram2_cs && dram_wait; + + always @(posedge clk) + begin + data_buf <= data_out; + if(read_enable) out_sel <= + ram1_cs ? SEL_RAM1 : + ram2_cs ? SEL_RAM2: + rom_cs ? SEL_ROM : + io_cs ? SEL_IO : + SEL_ERR; + end +endmodule diff --git a/rtl/src/palette.v b/rtl/src/palette.v new file mode 100644 index 0000000..d076453 --- /dev/null +++ b/rtl/src/palette.v @@ -0,0 +1,28 @@ +`timescale 1ns / 1ps +// taken from https://danstrother.com/2010/09/11/inferring-rams-in-fpgas/ +// modified for one read/write-port and one read-only-port, +/// A parameterized, inferable, true dual-port, dual-clock block RAM in Verilog. + +module palette #( + parameter SLOTS_WIDTH = 4, COLOR_WIDTH = 12 +) ( + input wire wr_clk, + input wire rd_clk, + input wire wr_en, + input wire [SLOTS_WIDTH-1:0] wr_slot, + input wire [COLOR_WIDTH-1:0] wr_data, + input wire [SLOTS_WIDTH-1:0] rd_slot, + output wire [COLOR_WIDTH-1:0] rd_data +); + +// Shared memory + reg [COLOR_WIDTH-1:0] colors [(2**SLOTS_WIDTH)-1:0]; + + assign rd_data = colors[rd_slot]; + + always @(posedge wr_clk) begin + if(wr_en) colors[wr_slot] <= wr_data; + end + +endmodule + diff --git a/rtl/src/sdspi.v b/rtl/src/sdspi.v new file mode 100644 index 0000000..7141288 --- /dev/null +++ b/rtl/src/sdspi.v @@ -0,0 +1,372 @@ +`timescale 1ns / 1ps + + +// Every spi_clk_div cpu clock cycles the spi clock line is inverted. +// So a spi clock cycle is 2*spi_clk_div cpu clock cycles. +// spi_clk_count counts the cpu cycles from spi_clk_div down to zero. +// The resulting spi clock frequency is: +// (cpu clock freq) / ((sclk_count + 1) * 2) +// So for a 83.33 MHz cpu clock, we get +// spi_clk_div = 10: 83.333 / 22 = 3.788 MHz +// spi_clk_div = 124: 83.333 / 250 = 333.33 KHz + + +module sdspi( + input wire clk, // bus clock + input wire reset, + + input wire[7:0] tx_data, // data to transmit + output wire[7:0] rx_data, // data received + output wire tx_ready, // ready to write a data byte + output wire tx_empty, // transmitter fifo is empty + output wire rx_avail, // a byte has been received + output wire rx_ovr, // receiver overrun + input wire tx_write, // write strobe + input wire rx_read, // read strobe (clears rx_ovr) + + output wire card_detect, // true is card is present + output wire card_changed, // card_detect signal has changed + output wire card_busy, // card is busy (MISO/DO is 0) + + input wire ctrl_write, // set the following flags + input wire rx_filter_en, // set to discard received $FF bytes + input wire txrx_en, // enable transmitter and receiver + input wire spiclk_f_en, // enable spi clock without cs + input wire spiclk_div_wr, // set clock divider via tx_data + + // PMOD connections + output wire sd_cs_n, + output reg sd_mosi, + input wire sd_miso, + output wire sd_sck, + input wire sd_cd + ); + + localparam CLKPHASE_0A = 2'b00; + localparam CLKPHASE_0B = 2'b01; + localparam CLKPHASE_1A = 2'b10; + localparam CLKPHASE_1B = 2'b11; + reg [1:0] clk_phase; + + reg xcvr_on; // if turned off, the rest of the current byte + // will still transmitted, and until then "running" + // will be 1 + (* KEEP *) + reg running; // transmitting/receiving a byte (maybe a dummy byte) + + (* KEEP *) reg [3:0] xcvr_bitcount; // number of bits left of the current byte + + reg [7:0] tx_shifter; + wire tx_fifo_wr_en; + reg tx_fifo_rd_en; + wire tx_fifo_full; + wire tx_fifo_empty; + wire [7:0] tx_fifo_out; + + reg [7:0] rx_shifter; + reg rx_filter; + reg rx_fifo_wr_en; + wire rx_fifo_rd_en; + wire rx_fifo_full; + wire rx_fifo_empty; + wire [7:0] rx_fifo_out; + + reg rx_bit_recvd; // this flag signals a received bit + + reg rx_overrun; // byte received when rx fifo is full + + reg c_changed; + reg c_cs; + + reg spi_clk; // the spi clock signal + reg spi_clk_on; // enable clock, either via init mode or by xcvr_on + reg spi_clk_f_on; // init clock mode, i.e. start clock but no tx/rx + reg [6:0] spi_clk_count; // counting cpu clock ticks + reg [6:0] spi_clk_div; // tick counter for spi clock phases + wire spi_clk_count_z = (spi_clk_count == 7'b0); + reg hphase_start; // start of a spi clock half-phase + + assign tx_ready = !tx_fifo_full; + assign tx_empty = tx_fifo_empty; + assign rx_avail = !rx_fifo_empty; + assign rx_ovr = rx_overrun; + assign rx_data = rx_fifo_out; + + assign card_busy = (sd_miso == 0); + assign card_changed = c_changed; + + assign sd_sck = spi_clk; + assign sd_cs_n = ~c_cs; + + assign card_detect = sd_cd; + + fifo #(.ADDR_WIDTH(4)) tx_fifo(clk, reset, + tx_fifo_wr_en, tx_fifo_rd_en, + tx_data, tx_fifo_out, + tx_fifo_full, + tx_fifo_empty + ); + + fifo #(.ADDR_WIDTH(8)) rx_fifo(clk, reset, + rx_fifo_wr_en, rx_fifo_rd_en, + rx_shifter, rx_fifo_out, + rx_fifo_full, + rx_fifo_empty + ); + + // spi clock + always @(posedge clk) + begin + if(reset) + begin + spi_clk <= 1; // CLK is high when inactive + spi_clk_on <= 0; + spi_clk_count <= 0; + end + else if(spi_clk_on) + begin + + // set spi_clk at start of every half-phase + if(hphase_start) + case(clk_phase) + CLKPHASE_0A: spi_clk <= 1'b0; + CLKPHASE_0B: spi_clk <= 1'b0; + CLKPHASE_1A: spi_clk <= 1'b1; + CLKPHASE_1B: spi_clk <= 1'b1; + endcase + + if(spi_clk_count_z) + begin + spi_clk_count <= spi_clk_div; + clk_phase <= clk_phase + 2'b1; + end + else + spi_clk_count <= spi_clk_count - 7'd1; + end + + // start the clock if needed + if( (spi_clk_on == 0) && (running || spi_clk_f_on)) + begin + spi_clk_on <= 1; + spi_clk_count <= spi_clk_div; + clk_phase <= CLKPHASE_1A; + end + + // turn off the clock if transceiver not running + // and the force-clock-on flag is not set + if( (spi_clk_on == 1) && (!running && !spi_clk_f_on)) + begin + spi_clk_on <= 0; + spi_clk <= 1'b1; + end + end + + // half-phase-start flag trails spi_clk_count_z by one tick + always @(posedge clk) + begin + if(reset) + hphase_start <= 0; + else + hphase_start <= spi_clk_on && spi_clk_count_z; + end + + // handle the force clock enable flag + always @(posedge clk) + begin + if (reset) + spi_clk_f_on <= 0; + else + if (ctrl_write) + spi_clk_f_on <= spiclk_f_en; + end + + // clock divider + always @(posedge clk) + begin + if (spiclk_div_wr) spi_clk_div <= tx_data[6:0]; + end + + // card_changed flag + always @(posedge clk) + begin + if(sd_cd) + c_changed <= 1; + else if(ctrl_write || reset) + c_changed <= 0; + end + + // cs signal + always @(posedge clk) + begin + if(hphase_start && clk_phase == CLKPHASE_0A || !running) + c_cs <= running; + end + + // transmitter + always @(posedge clk) + begin + if(reset) + begin + // ???? we start the bitcount at 1 because we start + // at the second clock phase where the bitcount + // is decremented and the next byte gets loaded + xcvr_bitcount <= 0; + + tx_shifter <= 8'b1; + xcvr_on <= 0; + sd_mosi <= 1; + tx_fifo_rd_en <= 0; + end + else + begin + // handle a control write to disable the transceiver + if(ctrl_write && !txrx_en && xcvr_on) + xcvr_on <= 0; + // a byte might still be in transit, so + // we do not disable the transceiver + // immediately (see "handle running status" below) + else + // handle control write to enable the transceiver + if(ctrl_write && txrx_en && !running) + begin + xcvr_on <= 1; + xcvr_bitcount <= 0; + // next clock phase must be 1B when starting the transceiver, + // so that the first byte is loaded into the shifter then + tx_shifter <= 8'b11111111; + // in case the transceiver is enabled, but no data is in the fifo, + // initialize the shifter with $FF + end + else + // handle clock phases + if (running) + begin + if(hphase_start) + case(clk_phase) + // set mosi signal at start of clock pulse + CLKPHASE_0A: sd_mosi <= tx_shifter[7]; + CLKPHASE_0B: ; + CLKPHASE_1A: begin // shift at rising clock + tx_shifter <= tx_shifter << 1; + xcvr_bitcount <= xcvr_bitcount - 1; + end + CLKPHASE_1B: begin // in the middle of the high clock pulse, + // fetch the next byte if there are no bits + // left in the shift register + if (xcvr_bitcount == 0) + begin + if(!tx_fifo_empty) + begin + tx_shifter <= tx_fifo_out; + tx_fifo_rd_en <= 1; + end + else + tx_shifter <= 8'b11111111; + xcvr_bitcount <= 8; + end + else + tx_fifo_rd_en <= 0; + end + endcase + else + tx_fifo_rd_en <= 0; + end + end + end + + // handle data write + assign tx_fifo_wr_en = tx_write && !tx_fifo_full; + + // Enable fifo read signal if fifo is not empty. + // The data at the fifo tail is always available at + // rx_data, the read signal just moves the tail pointer + // forward. + assign rx_fifo_rd_en = rx_read && !rx_fifo_empty; + + // receiver + always @(posedge clk) + begin + if(reset) + begin + rx_bit_recvd <= 0; + rx_shifter <= 8'b11111111; + rx_fifo_wr_en <= 0; + rx_filter <= 0; + rx_overrun <= 0; + end + else + begin + // handle a control write + if(ctrl_write) + begin + rx_filter <= rx_filter_en; + rx_overrun <= 0; + if(txrx_en && !running) + rx_shifter <= 8'b0; + end + + if (running && hphase_start) + case(clk_phase) + CLKPHASE_0A: ; + CLKPHASE_0B: ; + CLKPHASE_1A: ; + CLKPHASE_1B: begin // in the middle of the high clock pulse, + // sample MISO and put into shift register + // and shift at the same time + rx_shifter <= { rx_shifter[6:0],sd_miso}; + rx_bit_recvd <= 1; + end + endcase + + if (rx_bit_recvd && !sd_cs_n && clk_phase == CLKPHASE_1B) + begin + rx_bit_recvd <= 0; + + // if a complete byte was received, bitcount will be + // 8 because the transmitter has already loaded the next byte + // at this half-phase + if (xcvr_bitcount == 8) + begin + // discard $FF bytes if filter is enabled + if(!rx_filter || rx_shifter != 8'b11111111) + begin + if(rx_fifo_full) // discard received byte if fifo is full + rx_overrun <= 1; // and set overrun flag + else + rx_fifo_wr_en <= 1; // otherwise, enable fifo write strobe, + // fifo will take data from rx_shifter + end + + // turn off filter if a byte != $FF was received + if (rx_filter && rx_shifter != 8'b11111111) + rx_filter <= 0; + end + end + else + rx_fifo_wr_en <= 0; + + end + end + + // handle running status + // (especially keep transmitter running when there are still bits left to be + // transmitted) + always@(posedge clk) + begin + if (reset) + running <= 0; + else + begin + // if we want to turn the transceiver on, set running flag + if (!running && xcvr_on) + running <= 1; + + // when running and a byte has been transmitted, + // check if we should turn the transceiver off + if (running && hphase_start && xcvr_bitcount==0) + if(clk_phase == CLKPHASE_1B) + if (!xcvr_on) + running <= 0; + end + end +endmodule diff --git a/rtl/src/sdspi_testbench.v b/rtl/src/sdspi_testbench.v new file mode 100644 index 0000000..a4113fb --- /dev/null +++ b/rtl/src/sdspi_testbench.v @@ -0,0 +1,199 @@ +`timescale 1ns / 1ns +`default_nettype none + +module sdspi_testbench(); + parameter CLOCK_NS = 10; + integer i,j; + + reg[7:0] rx_testdata[0:3]; + reg[7:0] read_data; + + // Test signals + reg clk = 0; + reg reset = 0; + + reg[7:0] tx_data = 0; + wire[7:0] rx_data; + wire tx_ready; + wire tx_empty; + wire rx_avail; + wire rx_ovr; + reg tx_write = 0; + reg rx_read = 0; + + wire card_detect; + wire card_changed; + wire card_busy; + + reg ctrl_write = 0; + reg rx_filter_en = 0; + reg txrx_en = 0; + reg spiclk_f_en = 0; + reg spiclk_div_wr = 0; + + // PMOD connections + wire sd_cs_n; + wire sd_mosi; + reg sd_miso = 1; + wire sd_sck; + reg sd_cd = 1; + + // Unit Under Test + sdspi UUT ( + .clk(clk), + .reset(reset), + .tx_data(tx_data), + .rx_data(rx_data), + .tx_ready(tx_ready), + .tx_empty(tx_empty), + .rx_avail(rx_avail), + .rx_ovr(rx_ovr), + .tx_write(tx_write), + .rx_read(rx_read), + .card_detect(card_detect), + .card_changed(card_changed), + .card_busy(card_busy), + .ctrl_write(ctrl_write), + .rx_filter_en(rx_filter_en), + .txrx_en(txrx_en), + .spiclk_f_en(spiclk_f_en), + .spiclk_div_wr(spiclk_div_wr), + .sd_cs_n(sd_cs_n), + .sd_mosi(sd_mosi), + .sd_miso(sd_miso), + .sd_sck(sd_sck), + .sd_cd(sd_cd) + ); + + // testbench clock + always + #(CLOCK_NS/2) clk <= ~clk; + + initial + begin + rx_testdata[0] <= 'hFF; + rx_testdata[1] <= 'hFF; + rx_testdata[2] <= 'hCA; + rx_testdata[3] <= 'hFE; + + // issue reset + reset = 1'b1; + #10 + reset = 1'b0; + #10 + + // set clock divider + tx_data <= 3; + spiclk_div_wr <= 1'b1; + #10 + spiclk_div_wr <= 1'b0; + #10 + + // Card initialization phase, + // cycle the clock at least 74 times + // while cs is off and mosi is high . + // we do 32 cycles + spiclk_f_en <= 1'b1; + ctrl_write <= 1'b1; + #10 + spiclk_f_en <= 1'b0; + ctrl_write <= 1'b0; + #10 + for (i=0; i<32*16; i = i + 1) + #10; + spiclk_f_en <= 1'b0; + ctrl_write <= 1'b1; + #10 + ctrl_write <= 1'b0; + #10 + for (i=0; i<32*16; i = i + 1) + #10; + + // Write two bytes + tx_data <= 8'hAB; + tx_write <= 1'b1; + #10; + tx_data <= 8'hCD; + tx_write <= 1'b1; + #10; + tx_write <= 1'b0; + #10 + + // start transceiver, enable rx_filter + txrx_en <= 1'b1; + rx_filter_en <= 1'b1; + ctrl_write <= 1'b1; + #10 + txrx_en <= 1'b0; + rx_filter_en <= 1'b0; + ctrl_write <= 1'b0; + + for (i = 0; i < 2048; i = i + 1) + begin + if (!sd_cs_n && (i % 16)==15) sd_miso <= rx_testdata[(i/(16*8)) % 4][7 - (i/16 % 8)]; + #10; + end + tx_write <= 1'b0; + #10 + + // read from rx fifo + read_data <= rx_data; + #10 + $display("read data 1: %02h", read_data); + + + // strobe rx_read to go to next byte + rx_read <= 1'b1; + #10 // one cycle to transfer the data + rx_read <= 1'b0; + #10 // we need this extra cycle for the fifo tail to move + + read_data <= rx_data; + #10 + $display("read data 2: %02h", read_data); + + // strobe rx_read to go to next byte + rx_read <= 1'b1; + #10 + rx_read <= 1'b0; + #10 // we need this extra cycle for the fifo tail to move + + read_data <= rx_data; + #10 + $display("read data 3: %02h", read_data); + + + // set flag to turn transceiver off + txrx_en <= 1'b0; + ctrl_write <= 1'b1; + #10 + ctrl_write <= 1'b0; + #10; + + // wait for the transceiver to actually turn off + for (i=0; i<32*16; i = i + 1) + #10; + + #10 + // clear rx fifo + for(i=0; i<14; i = i + 1) + begin + $display("clear fifo data %02h", rx_data); + rx_read <= 1'b1; + #10 + rx_read <= 1'b0; + #10 + #10 + #10; // simulate the four cycles of an instruction + end + + $finish(); + end + + initial + begin + // Required to dump signals + $dumpfile("sdspi_tb_dump.vcd"); + $dumpvars(0); + end +endmodule diff --git a/rtl/src/stack.v b/rtl/src/stack.v new file mode 100644 index 0000000..965c070 --- /dev/null +++ b/rtl/src/stack.v @@ -0,0 +1,42 @@ +`timescale 1ns / 1ps +////////////////////////////////////////////////////////////////////////////////// +// Company: +// Engineer: +// +// Create Date: 17.01.2021 20:59:29 +// Design Name: +// Module Name: stack +// Project Name: +// Target Devices: +// Tool Versions: +// Description: +// +// Dependencies: +// +// Revision: +// Revision 0.01 - File Created +// Additional Comments: +// +////////////////////////////////////////////////////////////////////////////////// + + +module stack + #(parameter ADDR_WIDTH=4, DATA_WIDTH=16) + ( + input wire clk, + input wire [ADDR_WIDTH-1:0] rd_addr, + input wire [ADDR_WIDTH-1:0] wr_addr, + input wire wr_enable, + output wire [DATA_WIDTH-1:0] rd_data, + input wire [DATA_WIDTH-1:0] wr_data + ); + + reg [DATA_WIDTH-1:0] stack[0:2**ADDR_WIDTH-1]; + + always @(posedge clk) + begin + if(wr_enable) stack[wr_addr] <= wr_data; + end + + assign rd_data = stack[rd_addr]; +endmodule diff --git a/rtl/src/stackcpu.v b/rtl/src/stackcpu.v new file mode 100644 index 0000000..c65ae4e --- /dev/null +++ b/rtl/src/stackcpu.v @@ -0,0 +1,427 @@ +`timescale 1ns / 1ps +////////////////////////////////////////////////////////////////////////////////// + +module stackcpu #(parameter ADDR_WIDTH = 32, WIDTH = 32, + WORDSIZE = 4, WORDSIZE_SHIFT = 2) ( + input wire clk, + input wire rst, + + input wire irq, + + output reg [ADDR_WIDTH-1:0] addr, + input wire [WIDTH-1:0] data_in, + output wire read_enable, + output wire [WIDTH-1:0] data_out, + output wire write_enable, + input wire mem_wait, + + output wire led1, + output wire led2, + output wire led3, + + output wire [WIDTH-1:0] debug_out1, + output wire [WIDTH-1:0] debug_out2, + output wire [WIDTH-1:0] debug_out3, + output wire [WIDTH-1:0] debug_out4, + output wire [WIDTH-1:0] debug_out5, + output wire [WIDTH-1:0] debug_out6 + ); + + localparam EVAL_STACK_INDEX_WIDTH = 6; + + wire reset = !rst; + + (* KEEP *) reg [1:0] seq_state; + localparam FETCH = 2'b00; localparam DECODE = 2'b01; localparam EXEC = 2'b10; localparam MEM = 2'b11; + + (* KEEP*) reg [WIDTH-1:0] X, nX; + wire [WIDTH-1:0] Y; + (* KEEP *) reg [WIDTH-1:0] PC, nPC; + reg [WIDTH-1:0] RP, nRP; + reg [WIDTH-1:0] FP, BP; + reg [WIDTH-1:0] IV,IR; + + wire [WIDTH-1:0] pc_next_ins = PC + 2; + + reg [EVAL_STACK_INDEX_WIDTH-1:0] ESP, nESP; + reg stack_write; + + reg irq_pending; + + // eval stack + stack #(.ADDR_WIDTH(EVAL_STACK_INDEX_WIDTH), .DATA_WIDTH(WIDTH)) estack ( + .clk(clk), + .rd_addr(ESP), + .wr_addr(nESP), + .wr_enable(stack_write), + .rd_data(Y), + .wr_data(X) + ); + + reg [15:0] ins; + + wire [WIDTH-1:0] operand; + + // decoded instructions + wire ins_loadrel; + wire ins_load; + wire ins_loadc; + wire ins_store; + wire ins_aluop; + wire ins_ext; + wire ins_xfer; + wire ins_branch; + wire ins_cbranch; + + // decoded extended instructions + wire ins_mem, ins_loadi, ins_storei; + wire ins_fpadj; + wire ins_reg, ins_loadreg, ins_storereg; + wire ins_reg_fp, ins_reg_bp, ins_reg_rp; + wire ins_reg_iv, ins_reg_ir; + wire ins_reg_esp; + wire loadstore_base; + wire cbranch_n; + + wire xfer_x2p, xfer_r2p, xfer_p2r; + wire [1:0] xfer_rs; + + wire [3:0] aluop; + wire [1:0] aluop_sd; + wire aluop_x2y, aluop_ext; + + wire cmp_i, cmp_e, cmp_l; + + wire mem_read; + wire mem_write; + + wire x_is_zero; + // wire [WIDTH-1:0] y_plus_operand = Y + operand; + + wire x_equals_y = X == Y; + wire y_lessthan_x = $signed(Y) < $signed(X); + wire yx_unsigned_less = Y < X; + + reg [WIDTH-1:0] mem_write_data; + + wire mem_read_enable, mem_write_enable; + + assign read_enable = mem_read_enable; + assign data_out = mem_write_data; + assign write_enable = mem_write_enable; + + // debug output ------------------------------------------------------------------------------------ + assign led1 = reset; + assign led2 = ins_loadc; + assign led3 = ins_branch; +// assign debug_out1 = { mem_read_enable, mem_write_enable, x_is_zero, +// ins_branch, ins_aluop, y_lessthan_x, x_equals_y, {7{1'b0}}, seq_state}; +// assign debug_out2 = data_in; +// assign debug_out3 = nX; +// assign debug_out4 = nPC; +// assign debug_out5 = ins; +// assign debug_out6 = IV; + //-------------------------------------------------------------------------------------------------- + + // instruction decoding + assign ins_branch = (ins[15:13] == 3'b000); + assign ins_aluop = (ins[15:13] == 3'b001); + assign ins_store = (ins[15:13] == 3'b010); + assign ins_xfer = (ins[15:13] == 3'b011); + assign ins_load = (ins[15:13] == 3'b100); + assign ins_cbranch = (ins[15:13] == 3'b101); + assign ins_loadc = (ins[15:13] == 3'b110); + assign ins_ext = (ins[15:13] == 3'b111); + + // sub-decode LOAD/STORE + assign loadstore_base = ins[0]; + + // sub-decode CBRANCH + assign cbranch_n = ins[0]; + + // sub-decode XFER + assign xfer_x2p = ins[0]; + assign xfer_r2p = ins[7]; + assign xfer_p2r = ins[6]; + assign xfer_rs = ins[9:8]; + + // sub-decode OP + assign aluop = ins[12:9]; + assign aluop_x2y = ins[6]; + assign aluop_sd = ins[5:4]; + assign aluop_ext = ins[7]; + + // sub-decode OP.CMP + assign cmp_i = ins[2]; + assign cmp_e = ins[1]; + assign cmp_l = ins[0]; + + assign x_is_zero = X == {WIDTH{1'b0}}; + + // decode extended instructions + assign ins_reg = (ins_ext && ins[12:10] == 3'b000); + assign ins_mem = (ins_ext && ins[12:10] == 3'b001); + assign ins_loadi = (ins_mem && ins[9] == 1'b0); + assign ins_storei = (ins_mem && ins[9] == 1'b1); + assign ins_fpadj = (ins_ext && ins[12:10] == 3'b011); + assign ins_loadrel= (ins_ext && ins[12:10] == 3'b101); + + // sub-decode LOADREG/STOREREG + assign ins_loadreg = (ins_reg && ins[9] == 1'b0); + assign ins_storereg = (ins_reg && ins[9] == 1'b1); + assign ins_reg_fp = (ins_reg && ins[3:0] == 4'b0000); + assign ins_reg_bp = (ins_reg && ins[3:0] == 4'b0001); + assign ins_reg_rp = (ins_reg && ins[3:0] == 4'b0010); + assign ins_reg_iv = (ins_reg && ins[3:0] == 4'b0011); + assign ins_reg_ir = (ins_reg && ins[3:0] == 4'b0100); + assign ins_reg_esp = (ins_reg && ins[3:0] == 4'b0101); + + assign mem_read = ins_loadi || ins_load || ins_loadrel || (ins_xfer && xfer_r2p); + assign mem_write = ins_storei || ins_store || (ins_xfer && xfer_p2r); + + assign mem_read_enable = (seq_state == FETCH) || (seq_state == EXEC && mem_read); + assign mem_write_enable = (seq_state == MEM && mem_write); + + initial + begin + PC <= 0; nPC <= 0; seq_state <= MEM; + ESP <= -1; nESP <= -1; + addr <= 0; + FP <= 0; BP <= 0; RP <= 0; nRP <= 0; + IV <= 0; IR <= 0; + irq_pending <= 0; + end + + // instruction sequencer + always @(posedge clk) + begin + if(reset) + seq_state <= MEM; + else if(mem_wait == 1'b0) + case(seq_state) + FETCH: seq_state <= DECODE; + DECODE: seq_state <= EXEC; + EXEC: seq_state <= MEM; + MEM: seq_state <= FETCH; + default: seq_state <= FETCH; + endcase + end + + // operand register + assign operand = + (ins_load || ins_store || ins_branch || ins_cbranch) ? + { {(WIDTH-13){ins[12]}}, ins[12:1], 1'b0 } + : (ins_loadc) ? { {(WIDTH-13){ins[12]}}, ins[12:0] } // sign extend + : (ins_aluop || ins_mem) ? + { {(WIDTH-4){1'b0}}, ins[3:0] } + : (ins_loadrel) ? { {(WIDTH-10){1'b0}}, ins[9:0] } + : (ins_fpadj) ? { {(WIDTH-10){ins[9]}}, ins[9:0] } // sign extend + : { {WIDTH{1'b0}} }; + + // program counter + always @(posedge clk) + begin + if(reset) nPC <= 0; + else + case(seq_state) + EXEC: + if(ins_xfer && xfer_x2p) nPC <= X; + else if(ins_branch || (ins_cbranch && (x_is_zero != cbranch_n))) nPC <= PC + operand; + else nPC <= pc_next_ins; + MEM: + if(ins_xfer && xfer_r2p) nPC <= data_in; + else if(irq_pending) nPC <= IV; + endcase + end + + // return stack pointer + always @* + begin + if(seq_state == EXEC || seq_state == DECODE || seq_state == MEM) + begin + if (ins_xfer) nRP <= RP + + ({ {(ADDR_WIDTH-3){xfer_rs[1]}},xfer_rs} << WORDSIZE_SHIFT); + // sign extend xfer_rs and multiply by word size + else if (ins_storereg && ins_reg_rp) nRP <= X; + else nRP <= RP; + end + else nRP <= nRP; + end + + // instruction fetch + // depending on bit 1 of the PC, read either the upper or lower half word as an instruction + always @* if(seq_state == DECODE) ins <= PC[1] ? data_in[15:0] : data_in[31:16]; + + // RAM read/write + always @(posedge clk) + begin + if(reset) + begin + addr <= 0; + mem_write_data <= 0; + end + else + case(seq_state) + DECODE: + if(ins_load || ins_store) // read from address in BP/FP + offset + addr <= operand + ( loadstore_base ? BP: FP); + else if (ins_loadi) // read from address in X + addr <= X; + else if (ins_storei) // write to address in Y + addr <= Y; + else if (ins_loadrel) // read from address next to current instruction + addr <= PC + operand; + else if (ins_xfer && xfer_r2p) // read from return stack + addr <= RP; // use the current RP + else if (ins_xfer && xfer_p2r) // write to return stack + addr <= nRP; // use the new RP + EXEC: + begin + if (ins_store) + mem_write_data <= X; + else if (ins_storei) + mem_write_data <= X; + else if (ins_xfer && xfer_p2r) + mem_write_data <= pc_next_ins; + else + mem_write_data <= 0; + end + MEM: + if(!mem_wait) // do not change the address if mem_wait is active + begin + if(ins_xfer && xfer_r2p) addr <= data_in; // on RET take addr for next instruction from the data we just read from mem + else addr <= irq_pending ? IV : nPC; // prepare fetch cycle + end + endcase + end + + // X/ToS-Register + always @(posedge clk) + begin + if(reset) nX <= 0; + else + case(seq_state) + // default: nX <= X; + FETCH, DECODE:; + EXEC: + if(ins_loadc) nX <= operand; + else if(ins_cbranch || ins_store || ins_storereg || (ins_xfer && xfer_x2p)) nX <= Y; + else if(ins_storei) nX <= Y + operand; + else if(ins_loadreg && ins_reg_fp) nX <= FP; + else if(ins_loadreg && ins_reg_bp) nX <= BP; + else if(ins_loadreg && ins_reg_rp) nX <= RP; + else if(ins_loadreg && ins_reg_iv) nX <= IV; + else if(ins_loadreg && ins_reg_ir) nX <= IR; + else if(ins_loadreg && ins_reg_esp) nX <= ESP; + else if(ins_aluop) + begin + case(aluop) + 4'b0000: nX = X + Y; // ADD + 4'b0001: nX = Y - X; // SUB + 4'b0010: nX = ~X; // NOT + 4'b0011: nX = X & Y; // AND + 4'b0100: nX = X | Y; // OR + 4'b0101: nX = X ^ Y; // XOR + 4'b0110: nX = // CMP + cmp_i ^ ((cmp_e && x_equals_y) || (cmp_l && y_lessthan_x)); + 4'b0111: nX = Y; // Y + 4'b1000: nX = aluop_ext ? X >>> 1 : X >> 1; // SHR + 4'b1001: nX = operand[1] ? X << 2 : X << 1; // SHL + 4'b1010: nX = X + operand; // INC + 4'b1011: nX = X - operand; // DEC + 4'b1100: nX = // CMPU + cmp_i ^ ((cmp_e && x_equals_y) || (cmp_l && yx_unsigned_less)); + // 4'b1101: nX = X[7:0] << ((3 - Y[1:0]) << 3); // BPLC + 4'b1101: nX = Y[1:0] == 0 ? { X[7:0], 24'b0 } : + Y[1:0] == 1 ? { 8'b0, X[7:0], 16'b0 } : + Y[1:0] == 2 ? { 16'b0, X[7:0], 8'b0 } : + { 24'b0, X[7:0]}; // BPLC + 4'b1110: nX = { X[23:16], X[15:8], X[7:0], X[31:24] }; // BROT + 4'b1111: nX = { 24'b0, Y[1:0] == 0 ? X[31:24] : Y[1:0] == 1 ? X[23:16] : + Y[1:0] == 2 ? X[15: 8] : X[7:0] }; // BSEL +// 4'b1110: nX = X * Y; // MUL +// 4'b1111: nX = X / Y; // DIV + default: nX = X; + endcase + end + MEM: + if (ins_loadi || ins_load || ins_loadrel) + nX = data_in; + endcase + end + + // estack movement + wire [EVAL_STACK_INDEX_WIDTH-1:0] delta = + ((ins_load || ins_loadc || ins_loadreg || ins_loadrel)) ? 1 + : ((ins_aluop || ins_loadi || ins_storei || ins_xfer)) ? + { {(EVAL_STACK_INDEX_WIDTH-2){aluop_sd[1]}},aluop_sd} // sign extend + : ((ins_store || ins_cbranch || ins_xfer || ins_storereg)) ? -1 + : 0; + + + always @* + begin + if(reset) + nESP <= 0; + else + if(seq_state == EXEC) + begin + nESP = ESP + delta; + end + end + + always @(posedge clk) + begin + // when to write (old) X back to stack (new Y) + // stack write is a reg so it is 1 in the next cycle i.e. MEM state + stack_write <= (seq_state == EXEC && + (ins_load || ins_loadc || ins_loadrel || ins_loadreg + || ((ins_loadi || ins_storei || ins_aluop) && aluop_x2y))); + end + + // FP register + always @(posedge clk) + begin + if(seq_state == EXEC) + begin + if(ins_fpadj) FP <= FP + operand; + else if(ins_storereg && ins_reg_fp) FP <= X; + end + end + + // BP register + always @(posedge clk) if(seq_state == EXEC && ins_storereg && ins_reg_bp) BP <= X; + + // IV register + always @(posedge clk) + begin + if(reset) + IV <= 0; + else if(seq_state == EXEC && ins_storereg && ins_reg_iv) + IV <= X; + end + + // IR register + always @(posedge clk) + begin + if(seq_state == MEM && irq_pending) IR <= nPC; // use nPC as interrupt return addr + end + + // process irq + always @(posedge clk) + begin + if(seq_state == MEM && irq_pending && !(ins_xfer & xfer_r2p)) // in FETCH state, clear irq_pending. + irq_pending <= 0; + else + irq_pending <= irq_pending || irq; // else set irq_pending when irq is high + end + + // advance CPU state + always @ (posedge clk) + begin + if(reset) + { PC, X, ESP, RP } <= { {WIDTH{1'b0}}, {WIDTH{1'b0}}, {WIDTH{1'b0}}, {WIDTH{1'b0}} }; + else if(seq_state == FETCH) + { PC, X, ESP, RP } <= { nPC, nX, nESP, nRP}; + end +endmodule diff --git a/rtl/src/testbench.v b/rtl/src/testbench.v new file mode 100644 index 0000000..8d26bb4 --- /dev/null +++ b/rtl/src/testbench.v @@ -0,0 +1,54 @@ +`timescale 1ns/1ps +`default_nettype none + +module testbench(); + reg clk; + reg rst_n; + wire btn0; + wire sw0; + wire sw1; + wire led0; + wire led1; + wire led2; + wire led3; + wire uart_txd_in; + wire uart_rxd_out; + + wire [15:0] ddr3_dq; + wire [1:0] ddr3_dqs_n; + wire [1:0] ddr3_dqs_p; + wire [13:0] ddr3_addr; + wire [2:0] ddr3_ba; + wire ddr3_ras_n; + wire ddr3_cas_n; + wire ddr3_we_n; + wire ddr3_reset_n; + wire [0:0] ddr3_ck_p; + wire [0:0] ddr3_ck_n; + wire [0:0] ddr3_cke; + wire [0:0] ddr3_cs_n; + wire [1:0] ddr3_dm; + wire [0:0] ddr3_odt; + + integer t; + + top top0(clk, rst_n, btn0, sw0,sw1, led0, led1, led2, led3, uart_txd_in, uart_rxd_out, + ddr3_dq, ddr3_dqs_n, ddr3_dqs_p, ddr3_addr, ddr3_ba, ddr3_ras_n, ddr3_cas_n, + ddr3_we_n, ddr3_reset_n, ddr3_ck_p, ddr3_ck_n, ddr3_cke, ddr3_cs_n, ddr3_dm, ddr3_odt); + + initial begin + clk = 1; + t = 0; + rst_n = 0; + end + + always #5.0 clk = ~clk; + + always @(posedge clk) begin + t <= t + 1; + if (t == 2) + rst_n = 1; + if (t == 400) + $finish; + end +endmodule diff --git a/rtl/src/top.v b/rtl/src/top.v new file mode 100644 index 0000000..e79d611 --- /dev/null +++ b/rtl/src/top.v @@ -0,0 +1,288 @@ +`timescale 1ns / 1ps +// either define clock as clk (100MHz on Arty) +// or as clk_1hz for debugging + +`define clock cpuclk +`define clkfreq 83333333 +//`define clock clk +//`define clkfreq 100000000 +//`define clock clk_1hz +`define ENABLE_VGAFB +`define ENABLE_MICROSD + +module top( + input wire clk, + input wire rst, + input wire btn0, + input wire sw0, + input wire sw1, + output wire led0, + output wire led1, + output wire led2, + output wire led3, + input wire uart_txd_in, + output wire uart_rxd_out, + + // DDR3 SDRAM + inout wire [15:0] ddr3_dq, + inout wire [1:0] ddr3_dqs_n, + inout wire [1:0] ddr3_dqs_p, + + output wire [13:0] ddr3_addr, + output wire [2:0] ddr3_ba, + output wire ddr3_ras_n, + output wire ddr3_cas_n, + output wire ddr3_we_n, + output wire ddr3_reset_n, + output wire [0:0] ddr3_ck_p, + output wire [0:0] ddr3_ck_n, + output wire [0:0] ddr3_cke, + output wire [0:0] ddr3_cs_n, + output wire [1:0] ddr3_dm, + output wire [0:0] ddr3_odt + +`ifdef ENABLE_VGAFB + , + output wire [3:0] VGA_R, + output wire [3:0] VGA_G, + output wire [3:0] VGA_B, + + output wire VGA_HS_O, + output wire VGA_VS_O +`endif + +`ifdef ENABLE_MICROSD + , + output wire sd_cs_n, + output wire sd_mosi, + input wire sd_miso, + output wire sd_sck, + input wire sd_cd +`endif +); + + reg clk_1hz; + reg [31:0] counter; + + localparam ADDR_WIDTH = 32, WIDTH = 32, + ROMADDR_WIDTH = 11, IOADDR_WIDTH = 11, IOADDR_SEL = 4; + + wire [ADDR_WIDTH-1:0] mem_addr; + wire [WIDTH-1:0] mem_read_data; + wire [WIDTH-1:0] mem_write_data; + (* KEEP *) wire mem_wait; + + (* KEEP *) wire mem_read_enable; + (* KEEP *) wire mem_write_enable; + (* KEEP *) wire io_enable; + wire [WIDTH-1:0] io_rd_data; + wire [IOADDR_SEL-1:0] io_slot = mem_addr[IOADDR_WIDTH-1:IOADDR_WIDTH-IOADDR_SEL]; + + wire irq; + + // assign led0 = mem_wait; + + wire [WIDTH-1:0] debug_data1, debug_data2, + debug_data3, debug_data4, + debug_data5, debug_data6; + + assign led0 = debug_data6[0]; + + wire cpuclk, cpuclk_locked; + wire dram_refclk200; + wire pixclk; + cpu_clkgen cpuclk_0(~rst, clk, cpuclk, dram_refclk200, pixclk, cpuclk_locked); + + // DRAM -------------------------------------------------------------------------- + wire [ADDR_WIDTH-1:0] dram_addr; + wire [WIDTH-1:0] dram_read_data, dram_write_data; + wire dram_read_enable, dram_write_enable, dram_wait; + + dram_bridge dram_bridge0 (dram_addr, + dram_read_data, dram_write_data, dram_read_enable, dram_write_enable, dram_wait, + rst, cpuclk, dram_refclk200, + ddr3_dq, ddr3_dqs_n, ddr3_dqs_p, ddr3_addr, + ddr3_ba, ddr3_ras_n, ddr3_cas_n, ddr3_we_n, + ddr3_reset_n, ddr3_ck_p, ddr3_ck_n, ddr3_cke, + ddr3_cs_n, ddr3_dm, ddr3_odt); + + mem #(.ADDR_WIDTH(ADDR_WIDTH), .DATA_WIDTH(WIDTH)) mem0( + .clk(`clock), .rst_n(rst), .addr(mem_addr), + .data_out(mem_read_data), .read_enable(mem_read_enable), + .data_in(mem_write_data), .write_enable(mem_write_enable), + .io_enable(io_enable), + .io_rd_data(io_rd_data), + .mem_wait(mem_wait), + .dram_addr(dram_addr), + .dram_read_data(dram_read_data), + .dram_write_data(dram_write_data), + .dram_read_enable(dram_read_enable), + .dram_write_enable(dram_write_enable), + .dram_wait(dram_wait) + ); + +`ifdef ENABLE_VGAFB + localparam FB_ADDR_WIDTH = 14; + wire [FB_ADDR_WIDTH-1:0] fb_rd_addr; + wire [FB_ADDR_WIDTH-1:0] fb_wr_addr; + wire [WIDTH-1:0] fb_rd_data; + wire [WIDTH-1:0] fb_wr_data; + wire fb_rd_en, fb_wr_en; + + wire fb_cs_en = io_enable && (io_slot == 2); + + assign fb_rd_en = fb_cs_en && mem_read_enable; + assign fb_wr_en = fb_cs_en && mem_write_enable; + assign fb_wr_data = mem_write_data; + + vgafb vgafb0(`clock, pixclk, rst, + mem_addr[3:0], fb_rd_data, fb_wr_data, + fb_rd_en, fb_wr_en, + VGA_HS_O, VGA_VS_O, VGA_R, VGA_G, VGA_B); +`endif + + // SPI SD card controller ------------------------------------------------------------------- +`ifdef ENABLE_MICROSD + wire [7:0] spi_tx_data; + (*KEEP*) wire [7:0] spi_rx_data; + wire spi_tx_ready; // ready to transmit new data + wire spi_tx_empty; // tx fifo is empty + wire spi_rx_avail; // a byte has been received + wire spi_rx_ovr; // receiver overrun + wire spi_tx_write; // write strobe + wire spi_rx_read; // read strobe (clears rx_avail) + + wire spi_card_detect; // true is card is present + wire spi_card_changed; // card_detect signal has changed + wire spi_card_busy; // card is busy (MISO/DO is 0) + + wire spi_ctrl_write; // set the following flags + wire spi_rx_filter_en; // set to wait for start bit (1-to-0) when receiving + wire spi_txrx_en; // enable transmitter and receiver + wire spi_sclk_f_en; // enable spi clock without transceiver + wire spi_sclk_div_wr; // set clock divider from tx_data + + wire spi_cs; // cs signal for spi controller + wire [WIDTH-1:0] spi_rd_data; + + assign spi_cs = io_enable && (io_slot == 1); + + // spi read data: [ 0,...,0,cd,cc,cb,tr,te,ra,ro,d,d,d,d,d,d,d,d ] + // cd = card detect, cc = card changed, cb = card busy, + // tr = transmitter ready, te = tx fifo empty, + // ra = received byte available, ro = receive overrun, d = received byte + assign spi_rd_data = + { {WIDTH-15{1'b0}}, spi_card_detect, spi_card_changed, spi_card_busy, + spi_tx_ready, spi_tx_empty, + spi_rx_avail, spi_rx_ovr, spi_rx_data }; + + // spi write data: [ 0,...,0,CW,CF,Cx,Cc,Cd,DR,DW,d,d,d,d,d,d,d,d ] + // CW = control write, CF = enable receive filter, Cx = enable transceiver, + // Cc = force spi clock on, Cd = write clock divider, + // DR = read acknowledge, DW = data write, d = byte to be sent + assign spi_ctrl_write = spi_cs && mem_write_enable && mem_write_data[14]; + assign spi_rx_filter_en = mem_write_data[13]; + assign spi_txrx_en = mem_write_data[12]; + assign spi_sclk_f_en = mem_write_data[11]; + assign spi_sclk_div_wr = spi_cs && mem_write_enable && mem_write_data[10]; + assign spi_rx_read = mem_write_data[9]; + assign spi_tx_write = spi_cs && mem_write_enable && mem_write_data[8]; + assign spi_tx_data = mem_write_data[7:0]; + + sdspi sdspi0(.clk(`clock), .reset(~rst), + .tx_data(spi_tx_data), .rx_data(spi_rx_data), + .tx_ready(spi_tx_ready), .tx_empty(spi_tx_empty), + .rx_avail(spi_rx_avail), .rx_ovr(spi_rx_ovr), + .tx_write(spi_tx_write), .rx_read(spi_rx_read), + .card_detect(spi_card_detect), .card_changed(spi_card_changed), .card_busy(spi_card_busy), + // ctrl_write is used with rx_filter_en, txrx_en and spiclk_f_en + .ctrl_write(spi_ctrl_write), + .rx_filter_en(spi_rx_filter_en), .txrx_en(spi_txrx_en), .spiclk_f_en(spi_sclk_f_en), + // + .spiclk_div_wr(spi_sclk_div_wr), + .sd_cs_n(sd_cs_n), + .sd_mosi(sd_mosi), .sd_miso(sd_miso), .sd_sck(sd_sck), .sd_cd(sd_cd)); +`endif + + // UART ----------------------------------------------------------------------- + + // uart write data: [ 0, 0, 0, 0, 0, T, C, 0, c, c, c, c, c, c, c, c ] + // T = transmit enable, C = receiver clear, c = 8-bit-character + // uart read data: [ 0, 0, 0, 0, 0, 0, A, B, c, c, c, c, c, c, c, c ] + // A = char available, B = tx busy, c = 8-bit-character + wire uart_cs = io_enable && (io_slot == 0); + wire uart_tx_en = uart_cs && mem_write_enable && mem_write_data[10]; + wire uart_rx_clear = uart_cs && mem_write_enable && mem_write_data[9]; + wire uart_rx_avail; + wire uart_rx_busy, uart_tx_busy; + wire uart_err; + wire [7:0] uart_rx_data; + wire [7:0] uart_tx_data; + wire [31:0] uart_baud = 32'd115200; + wire [WIDTH-1:0] uart_rd_data; + + assign uart_tx_data = mem_write_data[7:0]; + assign uart_rd_data = { {WIDTH-10{1'b1}}, uart_rx_avail, uart_tx_busy, uart_rx_data }; + + reg timer_tick; + reg[23:0] tick_count; + wire [1:0] irq_in = { timer_tick, uart_rx_avail }; + wire [1:0] irqc_rd_data0; + wire [WIDTH-1:0] irqc_rd_data = { tick_count, 6'b0, irqc_rd_data0 }; + wire irqc_seten = mem_write_data[7]; + wire irqc_cs = io_enable && (io_slot == 3); + + assign io_rd_data = (io_slot == 0) ? uart_rd_data : + `ifdef ENABLE_MICROSD + (io_slot == 1) ? spi_rd_data : + `endif + `ifdef ENABLE_VGAFB + (io_slot == 2) ? fb_rd_data : + `endif + (io_slot == 3) ? irqc_rd_data: + + -1; + + buart #(.CLKFREQ(`clkfreq)) uart0(`clock, rst, + uart_baud, + uart_txd_in, uart_rxd_out, + uart_rx_clear, uart_tx_en, + uart_rx_avail, uart_tx_busy, + uart_tx_data, uart_rx_data); + + // CPU ----------------------------------------------------------------- + stackcpu cpu0(.clk(`clock), .rst(rst), .irq(irq), + .addr(mem_addr), + .data_in(mem_read_data), .read_enable(mem_read_enable), + .data_out(mem_write_data), .write_enable(mem_write_enable), + .mem_wait(mem_wait), + .led1(led1), .led2(led2), .led3(led3), + .debug_out1(debug_data1), + .debug_out2(debug_data2), + .debug_out3(debug_data3), + .debug_out4(debug_data4), + .debug_out5(debug_data5), + .debug_out6(debug_data6)); + + // Interrupt Controller + irqctrl irqctrl0(`clock, irq_in, irqc_cs, mem_write_enable, + irqc_seten, irqc_rd_data0, + irq); + + // count clock ticks + // generate interrupt every 20nth of a second + always @ (posedge `clock) + begin + counter <= counter + 1; + if (counter >= (`clkfreq/20)) + begin + counter <= 0; + timer_tick <= 1; + tick_count <= tick_count + 1'b1; + end + else + begin + timer_tick <= 0; + end + end +endmodule diff --git a/rtl/src/uart.v b/rtl/src/uart.v new file mode 100644 index 0000000..fec26a3 --- /dev/null +++ b/rtl/src/uart.v @@ -0,0 +1,262 @@ +/* +Copyright (c) 2010-2020, James Bowman +All rights reserved. + +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. + +* Neither the name of swapforth nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +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 HOLDER 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. +*/ + + +`default_nettype none +//`define def_clkfreq 100000000 +`define def_clkfreq 83333333 + +module baudgen( + input wire clk, + input wire resetq, + input wire [31:0] baud, + input wire restart, + output wire ser_clk); + parameter CLKFREQ = `def_clkfreq; + + wire [38:0] aclkfreq = CLKFREQ; + reg [38:0] d; + wire [38:0] dInc = d[38] ? ({4'd0, baud}) : (({4'd0, baud}) - aclkfreq); + wire [38:0] dN = restart ? 0 : (d + dInc); + wire fastclk = ~d[38]; + assign ser_clk = fastclk; + + always @(negedge resetq or posedge clk) + begin + if (!resetq) begin + d <= 0; + end else begin + d <= dN; + end + end +endmodule + +/* + +-----+ +-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+---- + | | | | | | | | | | | | + |start| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |stop1|stop2| + | | | | | | | | | | | ? | + +-----+-----+-----+-----+-----+-----+-----+-----+-----+ + + +*/ + +module uart( + input wire clk, // System clock + input wire resetq, + + // Outputs + output wire uart_busy, // High means UART is transmitting + output reg uart_tx, // UART transmit wire + // Inputs + input wire [31:0] baud, + input wire uart_wr_i, // Raise to transmit byte + input wire [7:0] uart_dat_i // 8-bit data +); + parameter CLKFREQ = `def_clkfreq; + + reg [3:0] bitcount; + reg [8:0] shifter; + + assign uart_busy = |bitcount; + wire sending = |bitcount; + + wire ser_clk; + + wire starting = uart_wr_i & ~uart_busy; + baudgen #(.CLKFREQ(CLKFREQ)) _baudgen( + .clk(clk), + .resetq(resetq), + .baud(baud), + .restart(1'b0), + .ser_clk(ser_clk)); + + always @(negedge resetq or posedge clk) + begin + if (!resetq) begin + uart_tx <= 1; + bitcount <= 0; + shifter <= 0; + end else begin + if (starting) begin + shifter <= { uart_dat_i[7:0], 1'b0 }; + bitcount <= 1 + 8 + 1; + end + + if (sending & ser_clk) begin + { shifter, uart_tx } <= { 1'b1, shifter }; + bitcount <= bitcount - 4'd1; + end + end + end + +endmodule + +module rxuart( + input wire clk, + input wire resetq, + input wire [31:0] baud, + input wire uart_rx, // UART recv wire + input wire rd, // read strobe + output wire valid, // has data + output wire [7:0] data); // data + parameter CLKFREQ = `def_clkfreq; + + reg [4:0] bitcount; + reg [7:0] shifter; + + // On starting edge, wait 3 half-bits then sample, and sample every 2 bits thereafter + + wire idle = &bitcount; + wire sample; + reg [2:0] hh = 3'b111; + wire [2:0] hhN = {hh[1:0], uart_rx}; + wire startbit = idle & (hhN[2:1] == 2'b10); + wire [7:0] shifterN = sample ? {hh[1], shifter[7:1]} : shifter; + + wire ser_clk; + baudgen #(.CLKFREQ(CLKFREQ)) _baudgen( + .clk(clk), + .baud({baud[30:0], 1'b0}), + .resetq(resetq), + .restart(startbit), + .ser_clk(ser_clk)); + + assign valid = (bitcount == 18); + reg [4:0] bitcountN; + always @* + if (startbit) + bitcountN = 0; + else if (!idle & !valid & ser_clk) + bitcountN = bitcount + 5'd1; + else if (valid & rd) + bitcountN = 5'b11111; + else + bitcountN = bitcount; + + // 3,5,7,9,11,13,15,17 + assign sample = (bitcount > 2) & bitcount[0] & !valid & ser_clk; + assign data = shifter; + + always @(negedge resetq or posedge clk) + begin + if (!resetq) begin + hh <= 3'b111; + bitcount <= 5'b11111; + shifter <= 0; + end else begin + hh <= hhN; + bitcount <= bitcountN; + shifter <= shifterN; + end + end +endmodule + +module fifo_rxuart( + input wire clk, + input wire resetq, + input wire [31:0] baud, + input wire uart_rx, // UART recv wire + input wire rd, // read strobe + output wire valid, // has data + output wire [7:0] data); // data + parameter CLKFREQ = `def_clkfreq; + + localparam ADDR_WIDTH = 6; + localparam DATA_WIDTH = 8; + + reg fifo_wr_en; + (*KEEP*) wire fifo_rd_en, fifo_full, fifo_empty; + wire [DATA_WIDTH-1:0] fifo_wr_data, fifo_rd_data; + (*KEEP*) wire rx_avail; + + assign valid = !fifo_empty; + assign data = fifo_rd_data; + assign fifo_rd_en = rd; + + fifo #(.ADDR_WIDTH(ADDR_WIDTH)) rx_fifo(clk, ~resetq, + fifo_wr_en, fifo_rd_en, + fifo_wr_data, fifo_rd_data, + fifo_full, + fifo_empty + ); + + rxuart #(.CLKFREQ(CLKFREQ)) _rx ( + .clk(clk), + .resetq(resetq), + .baud(baud), + .uart_rx(uart_rx), + .rd(fifo_wr_en), // strobe read signal on fifo write + .valid(rx_avail), + .data(fifo_wr_data)); + + always @(posedge clk) + begin + if (!resetq) + fifo_wr_en <= 0; + else if(!fifo_wr_en && rx_avail) // ILA shows fifo_wr_en stays 0 ?? + fifo_wr_en <= 1; // pulse fifo_wr_en for one clock + else // rx_avail goes zero one clock later + fifo_wr_en <= 0; + end +endmodule + +module buart( + input wire clk, + input wire resetq, + input wire [31:0] baud, + input wire rx, // recv wire + output wire tx, // xmit wire + input wire rd, // read strobe + input wire wr, // write strobe + output wire valid, // has recv data + output wire busy, // is transmitting + input wire [7:0] tx_data, + output wire [7:0] rx_data // data +); + parameter CLKFREQ = `def_clkfreq; + + fifo_rxuart #(.CLKFREQ(CLKFREQ)) _rx ( + .clk(clk), + .resetq(resetq), + .baud(baud), + .uart_rx(rx), + .rd(rd), + .valid(valid), + .data(rx_data)); + uart #(.CLKFREQ(CLKFREQ)) _tx ( + .clk(clk), + .resetq(resetq), + .baud(baud), + .uart_busy(busy), + .uart_tx(tx), + .uart_wr_i(wr), + .uart_dat_i(tx_data)); +endmodule diff --git a/rtl/src/uart_tb.v b/rtl/src/uart_tb.v new file mode 100644 index 0000000..7f794a2 --- /dev/null +++ b/rtl/src/uart_tb.v @@ -0,0 +1,100 @@ +////////////////////////////////////////////////////////////////////// +// File Downloaded from http://www.nandland.com +////////////////////////////////////////////////////////////////////// + +// This testbench will exercise both the UART Tx and Rx. +// It sends out byte 0xAB over the transmitter +// It then exercises the receive by receiving byte 0x3F +`timescale 1ns/10ps + +module uart_tb (); + + // Testbench uses a 10 MHz clock + // Want to interface to 115200 baud UART + // 10000000 / 115200 = 87 Clocks Per Bit. + parameter c_CLOCK_PERIOD_NS = 100; + parameter c_CLKS_PER_BIT = 87; + parameter c_BIT_PERIOD = 8600; + + reg r_Clock = 0; + reg r_Tx_DV = 0; + wire w_Tx_Done; + reg [7:0] r_Tx_Byte = 0; + reg r_Rx_Serial = 1; + wire [7:0] w_Rx_Byte; + + + // Takes in input byte and serializes it + task UART_WRITE_BYTE; + input [7:0] i_Data; + integer ii; + begin + + // Send Start Bit + r_Rx_Serial <= 1'b0; + #(c_BIT_PERIOD); + #1000; + + + // Send Data Byte + for (ii=0; ii<8; ii=ii+1) + begin + r_Rx_Serial <= i_Data[ii]; + #(c_BIT_PERIOD); + end + + // Send Stop Bit + r_Rx_Serial <= 1'b1; + #(c_BIT_PERIOD); + end + endtask // UART_WRITE_BYTE + + + uart_rx #(.CLKS_PER_BIT(c_CLKS_PER_BIT)) UART_RX_INST + (.i_Clock(r_Clock), + .i_Rx_Serial(r_Rx_Serial), + .o_Rx_DV(), + .o_Rx_Byte(w_Rx_Byte) + ); + + uart_tx #(.CLKS_PER_BIT(c_CLKS_PER_BIT)) UART_TX_INST + (.i_Clock(r_Clock), + .i_Tx_DV(r_Tx_DV), + .i_Tx_Byte(r_Tx_Byte), + .o_Tx_Active(), + .o_Tx_Serial(), + .o_Tx_Done(w_Tx_Done) + ); + + + always + #(c_CLOCK_PERIOD_NS/2) r_Clock <= !r_Clock; + + + // Main Testing: + initial + begin + + // Tell UART to send a command (exercise Tx) + @(posedge r_Clock); + @(posedge r_Clock); + r_Tx_DV <= 1'b1; + r_Tx_Byte <= 8'hAB; + @(posedge r_Clock); + r_Tx_DV <= 1'b0; + @(posedge w_Tx_Done); + + // Send a command to the UART (exercise Rx) + @(posedge r_Clock); + UART_WRITE_BYTE(8'h3F); + @(posedge r_Clock); + + // Check that the correct command was received + if (w_Rx_Byte == 8'h3F) + $display("Test Passed - Correct Byte Received"); + else + $display("Test Failed - Incorrect Byte Received"); + + end + +endmodule \ No newline at end of file diff --git a/rtl/src/vgafb.v b/rtl/src/vgafb.v new file mode 100644 index 0000000..4e8d668 --- /dev/null +++ b/rtl/src/vgafb.v @@ -0,0 +1,292 @@ +`timescale 1ns / 1ps +`default_nettype none + +// Project F: Display Timings +// (C)2019 Will Green, Open Source Hardware released under the MIT License +// Learn more at https://projectf.io + +//128K video memory is not enough for 640x480x4 +`define RES_640_400 +//`define RES_1024_768 + +module display_timings #( + H_RES=640, // horizontal resolution (pixels) + V_RES=480, // vertical resolution (lines) + H_FP=16, // horizontal front porch + H_SYNC=96, // horizontal sync + H_BP=48, // horizontal back porch + V_FP=10, // vertical front porch + V_SYNC=2, // vertical sync + V_BP=33, // vertical back porch + H_POL=0, // horizontal sync polarity (0:neg, 1:pos) + V_POL=0 // vertical sync polarity (0:neg, 1:pos) + ) + ( + input wire i_pix_clk, // pixel clock + input wire i_rst, // reset: restarts frame (active high) + output wire o_hs, // horizontal sync + output wire o_vs, // vertical sync + output wire o_de, // display enable: high during active video + output wire o_frame, // high for one tick at the start of each frame + output wire o_scanline, // high for one tick at the start of each scanline + output reg o_vblank, // high during vertical blank phase + output reg signed [15:0] o_sx, // horizontal beam position (including blanking) + output reg signed [15:0] o_sy // vertical beam position (including blanking) + ); + + // Horizontal: sync, active, and pixels + localparam signed H_STA = 0 - H_FP - H_SYNC - H_BP; // horizontal start + localparam signed HS_STA = H_STA + H_FP; // sync start + localparam signed HS_END = HS_STA + H_SYNC; // sync end + localparam signed HA_STA = 0; // active start + localparam signed HA_END = H_RES - 1; // active end + + // Vertical: sync, active, and pixels + localparam signed V_STA = 0 - V_FP - V_SYNC - V_BP; // vertical start + localparam signed VS_STA = V_STA + V_FP; // sync start + localparam signed VS_END = VS_STA + V_SYNC; // sync end + localparam signed VA_STA = 0; // active start + localparam signed VA_END = V_RES - 1; // active end + + // generate sync signals with correct polarity + assign o_hs = H_POL ? (o_sx > HS_STA && o_sx <= HS_END) + : ~(o_sx > HS_STA && o_sx <= HS_END); + assign o_vs = V_POL ? (o_sy > VS_STA && o_sy <= VS_END) + : ~(o_sy > VS_STA && o_sy <= VS_END); + + // display enable: high during active period + assign o_de = (o_sx >= 0 && o_sy >= 0); + + // o_frame: high for one tick at the start of each frame + assign o_frame = (o_sy == V_STA && o_sx == H_STA); + // o_scanline: high for one tick at the start of each visible scanline + assign o_scanline = (o_sy >= VA_STA) && (o_sy <= VA_END) && (o_sx == H_STA); + + always @(posedge i_pix_clk) + begin + if(o_frame) o_vblank <= 1; + else if (o_de) o_vblank <= 0; + end + + always @ (posedge i_pix_clk) + begin + if (i_rst) // reset to start of frame + begin + o_sx <= H_STA; + o_sy <= V_STA; + end + else + begin + if (o_sx == HA_END) // end of line + begin + o_sx <= H_STA; + if (o_sy == VA_END) // end of frame + o_sy <= V_STA; + else + o_sy <= o_sy + 16'sh1; + end + else + o_sx <= o_sx + 16'sh1; + end + end +endmodule + +// Project F: Display Controller VGA Demo +// (C)2020 Will Green, Open source hardware released under the MIT License +// Learn more at https://projectf.io + +// This demo requires the following Verilog modules: +// * display_clocks +// * display_timings +// * test_card_simple or another test card + +module vgafb #(VMEM_ADDR_WIDTH = 15, VMEM_DATA_WIDTH = 32) ( + input wire cpu_clk, // cpu clock + input wire CLK, // pixel clock + input wire RST_BTN, // reset button + input wire[3:0] reg_sel, // register select/address + output wire [VMEM_DATA_WIDTH-1:0] rd_data, + input wire [VMEM_DATA_WIDTH-1:0] wr_data, + input wire rd_en, + input wire wr_en, + + output wire VGA_HS, // horizontal sync output + output wire VGA_VS, // vertical sync output + output wire [3:0] VGA_R, // 4-bit VGA red output + output wire [3:0] VGA_G, // 4-bit VGA green output + output wire [3:0] VGA_B // 4-bit VGA blue output + ); + + localparam BITS_PER_PIXEL = 4; localparam MAX_SHIFT_COUNT = 7; + localparam REG_RD_ADDR = 0; localparam REG_WR_ADDR = 1; localparam REG_VMEM = 2; + localparam REG_PAL_SLOT = 3; localparam REG_PAL_DATA = 4; + localparam REG_CTL = 5; + + localparam COLOR_WIDTH = 12; + localparam PALETTE_WIDTH = 4; + + // Display Clocks + wire pix_clk = CLK; // pixel clock + wire clk_lock = 1; // clock locked? + + wire vmem_rd_en; + wire vmem_wr_en; + wire [VMEM_DATA_WIDTH-1:0] vmem_rd_data; + reg [VMEM_ADDR_WIDTH-1:0] cpu_rd_addr; + reg [VMEM_ADDR_WIDTH-1:0] cpu_wr_addr; + reg [VMEM_ADDR_WIDTH-1:0] pix_addr; + wire [VMEM_DATA_WIDTH-1:0] pix_data; + wire pix_rd; + wire [VMEM_DATA_WIDTH-1:0] status; + + assign vmem_rd_en = rd_en; + assign vmem_wr_en = (reg_sel == REG_VMEM) && wr_en; + assign rd_data = (reg_sel == REG_VMEM) ? vmem_rd_data : + (reg_sel == REG_RD_ADDR) ? cpu_rd_addr : + (reg_sel == REG_WR_ADDR) ? cpu_wr_addr : + (reg_sel == REG_CTL) ? status : + 32'hFFFFFFFF; + + wire [VMEM_ADDR_WIDTH-1:0] cpu_addr = vmem_wr_en ? cpu_wr_addr : cpu_rd_addr; + + bram_tdp #(.DATA(VMEM_DATA_WIDTH),.ADDR(VMEM_ADDR_WIDTH)) vram0 ( + .a_rd(vmem_rd_en), .a_clk(cpu_clk), + .a_wr(vmem_wr_en), .a_addr(cpu_addr), .a_din(wr_data), + .a_dout(vmem_rd_data), + .b_clk(pix_clk), .b_addr(pix_addr), .b_dout(pix_data), + .b_rd(pix_rd) + ); + + wire palette_wr_en = (reg_sel == REG_PAL_DATA) && wr_en; + reg [PALETTE_WIDTH-1:0] palette_wr_slot; + wire [COLOR_WIDTH-1:0] color_data; + + palette palette0(.wr_clk(cpu_clk), .rd_clk(pix_clk), .wr_en(palette_wr_en), + .wr_slot(palette_wr_slot), .wr_data(wr_data[COLOR_WIDTH-1:0]), + .rd_slot(pixel[3:0]), .rd_data(color_data)); + + // Display Timings + wire signed [15:0] sx; // horizontal screen position (signed) + wire signed [15:0] sy; // vertical screen position (signed) + wire h_sync; // horizontal sync + wire v_sync; // vertical sync + wire de; // display enable + wire frame; // frame start + wire scanline; // scanline start + wire vblank; // vertical blank + reg vblank_buf; // vertical blank in cpu clock domain + + display_timings #( // 640x480 800x600 1280x720 1920x1080 +`ifdef RES_1024_768 + .H_RES(1024), // 640 800 1280 1920 + .V_RES(768), // 480 600 720 1080 + .H_FP(24), // 16 40 110 88 + .H_SYNC(136), // 96 128 40 44 + .H_BP(160), // 48 88 220 148 + .V_FP(3), // 10 1 5 4 + .V_SYNC(6), // 2 4 5 5 + .V_BP(29), // 33 23 20 36 + .H_POL(0), // 0 1 1 1 + .V_POL(0) // 0 1 1 1 + `endif + `ifdef RES_640_400 + .H_RES(640), + .V_RES(400), + .H_FP(16), + .H_SYNC(96), + .H_BP(48), + .V_FP(12), + .V_SYNC(2), + .V_BP(35), + .H_POL(0), + .V_POL(1) + `endif + ) + display_timings_inst ( + .i_pix_clk(CLK), + .i_rst(!RST_BTN), + .o_hs(h_sync), + .o_vs(v_sync), + .o_de(de), + .o_frame(frame), + .o_scanline(scanline), + .o_vblank(vblank), + .o_sx(sx), + .o_sy(sy) + ); + + wire [7:0] red; + wire [7:0] green; + wire [7:0] blue; + + reg [VMEM_DATA_WIDTH-1:0] shifter; + reg [4:0] shift_count; + + // delayed frame signal for pix_rd + reg frame_d; + + assign pix_rd = frame_d || scanline || (shift_count == 2); + + assign status = { 4'b0001, {(VMEM_DATA_WIDTH-5){1'b0}}, vblank_buf}; + + wire [BITS_PER_PIXEL-1:0] pixel = shifter[VMEM_DATA_WIDTH-1:VMEM_DATA_WIDTH-BITS_PER_PIXEL]; + + always @(posedge pix_clk) frame_d <= frame; + + always @(posedge cpu_clk) vblank_buf <= vblank; + + always @(posedge cpu_clk) + begin + if(wr_en) + begin + case(reg_sel) + REG_RD_ADDR: cpu_rd_addr <= wr_data; + REG_WR_ADDR: cpu_wr_addr <= wr_data; + REG_VMEM: cpu_wr_addr <= cpu_wr_addr + 1; // auto-increment write addr on write + REG_PAL_SLOT: palette_wr_slot <= wr_data[3:0]; + endcase + end + else + if(rd_en && reg_sel == REG_VMEM) cpu_rd_addr <= cpu_rd_addr + 1; // auto-increment read addr on read + end + + always @(posedge pix_clk) + begin + if(scanline || shift_count == MAX_SHIFT_COUNT) // before start of a line + begin // or at the end of a word, reset shifter with pixel data + shift_count <= 0; + shifter <= pix_data; + end + else if(de) + begin + shift_count <= shift_count + 1; + shifter <= shifter << BITS_PER_PIXEL; + end + + if(frame) // at start of frame, reset pixel pointer + pix_addr <= 0; + else if(shift_count == 1) // after the first pixel, increment address + pix_addr <= pix_addr + 1; + end + +// Hard-Coded RGBI palette +// // Pixel = { red, green, blue, intensity } +// assign red = pixel[3] ? pixel[0] ? 255 : 127: 0; +// assign green = pixel[2] ? pixel[0] ? 255 : 127: 0; +// assign blue = pixel[1] ? pixel[0] ? 255 : 127: 0; + +// // VGA Output +// // VGA Pmod is 12-bit so we take the upper nibble of each colour +// assign VGA_HS = h_sync; +// assign VGA_VS = v_sync; +// assign VGA_R = de ? red[7:4] : 4'b0; +// assign VGA_G = de ? green[7:4] : 4'b0; +// assign VGA_B = de ? blue[7:4] : 4'b0; + + // 12 bit RGB palette + assign VGA_HS = h_sync; + assign VGA_VS = v_sync; + assign VGA_R = de ? color_data[11:8] : 4'b0; + assign VGA_G = de ? color_data[7:4] : 4'b0; + assign VGA_B = de ? color_data[3:0] : 4'b0; +endmodule diff --git a/tridoraemu/README.md b/tridoraemu/README.md index f7ac81c..0ec332b 100644 --- a/tridoraemu/README.md +++ b/tridoraemu/README.md @@ -23,7 +23,7 @@ On the first run, this may take a while as the go build system fetches some exte Start the *tridoraemu* binary in the same directory as the SD-Card image file (*sdcard.img*) and the ROM file (*rommon.prog*). It needs to be started on the command line as it uses the terminal window for the serial console. On startup, the emulator opens the VGA framebuffer window which is only used for graphics output. -The Tridora software (esp. the editor) requires a decent vt100-compatible (plus colors) terminal emulator. It has been successfully tested with (new) Windows Terminal, WezTerm and xterm. +The Tridora software (esp. the editor) requires a decent vt100-compatible (plus colors) terminal emulator. It has been successfully tested with (new) Windows Terminal, Alacritty, WezTerm and xterm. The color scheme in the editor is meant for a dark terminal background.