some more array asm

This commit is contained in:
Irmen de Jong 2019-08-04 15:33:00 +02:00
parent b842493cf0
commit a1cd202cd2
8 changed files with 367 additions and 86 deletions

View File

@ -827,6 +827,13 @@ internal class AstChecker(private val program: Program,
else
printWarning("result values of subroutine call are discarded", functionCallStatement.position)
}
if(functionCallStatement.target.nameInSource.last() in setOf("lsl", "lsr", "rol", "ror", "rol2", "ror2", "swap")) {
// in-place modification, can't be done on literals
if(functionCallStatement.arglist.any { it !is IdentifierReference && it !is RegisterExpr && it !is ArrayIndexedExpression && it !is DirectMemoryRead }) {
checkResult.add(ExpressionError("can't use that as argument to a in-place modifying function", functionCallStatement.position))
}
}
super.visit(functionCallStatement)
}

View File

@ -60,7 +60,7 @@ fun compileProgram(filepath: Path,
programAst.removeNopsFlattenAnonScopes()
// if you want to print the AST, do it before shuffling the statements around below
// printAst(programAst)
printAst(programAst)
programAst.reorderStatements() // reorder statements and add type casts, to please the compiler later
@ -88,6 +88,8 @@ fun compileProgram(filepath: Path,
programAst.checkValid(compilerOptions) // check if final tree is valid
programAst.checkRecursion() // check if there are recursive subroutine calls
printAst(programAst)
if(writeAssembly) {
// asm generation directly from the Ast, no need for intermediate code
val zeropage = MachineDefinition.C64Zeropage(compilerOptions)

View File

@ -21,11 +21,12 @@ class AnonymousScopeVarsCleanup(val program: Program): IAstModifyingVisitor {
super.visit(program)
for((scope, decls) in varsToMove) {
val sub = scope.definingSubroutine()!!
val existingVariables = sub.statements.filterIsInstance<VarDecl>().map { it.name }.toSet()
val existingVariables = sub.statements.filterIsInstance<VarDecl>().associate { it.name to it }
var conflicts = false
decls.forEach {
if (it.name in existingVariables) {
checkResult.add(NameError("variable ${it.name} already exists in subroutine ${sub.name}", it.position))
val existing = existingVariables[it.name]
if (existing!=null) {
checkResult.add(NameError("variable ${it.name} already defined in subroutine ${sub.name} at ${existing.position}", it.position))
conflicts = true
}
}

View File

@ -233,7 +233,7 @@ internal class AsmGen2(val program: Program,
}
}
else {
throw AssemblyError("huh, var is already on zp $zpVar")
throw AssemblyError("huh, var is already in zp $fullName")
// it was already allocated on the zp, what to do?
// out("${variable.name} = ${zpVar.first}\t; zp ${zpVar.second}")
}
@ -469,7 +469,7 @@ internal class AsmGen2(val program: Program,
+ sta $destination
"""
private fun asmIdentifierName(identifier: IdentifierReference): String {
internal fun asmIdentifierName(identifier: IdentifierReference): String {
val name = if(identifier.memberOfStruct(program.namespace)!=null) {
identifier.targetVarDecl(program.namespace)!!.name
} else {
@ -519,7 +519,8 @@ internal class AsmGen2(val program: Program,
return false
}
private fun readAndPushArrayvalueWithIndexA(arrayDt: DataType, variablename: String) {
private fun readAndPushArrayvalueWithIndexA(arrayDt: DataType, variable: IdentifierReference) {
val variablename = asmIdentifierName(variable)
when (ArrayElementTypes.getValue(arrayDt).memorySize()) {
1 -> {}
2 -> out(" asl a")
@ -530,11 +531,13 @@ internal class AsmGen2(val program: Program,
DataType.STR, DataType.STR_S, DataType.ARRAY_UB, DataType.ARRAY_B ->
out(" tay | lda $variablename,y | sta $ESTACK_LO_HEX,x | dex")
DataType.ARRAY_UW, DataType.ARRAY_W ->
out(" tay | lda $variablename,y | sta $ESTACK_LO_HEX,x | iny | lda $variablename,y | sta $ESTACK_HI_HEX,x | dex")
out(" tay | lda $variablename,y | sta $ESTACK_LO_HEX,x | lda $variablename+1,y | sta $ESTACK_HI_HEX,x | dex")
DataType.ARRAY_F ->
out("""
sta $ESTACK_LO_HEX,x
dex
lda #<$variablename
ldy #>$variablename
jsr c64flt.push_float_from_indexed_var
""")
else ->
@ -1526,15 +1529,38 @@ $endLabel""")
}
}
is PrefixExpression -> {
// TODO optimize common cases
translateExpression(assign.value as PrefixExpression)
assignFromEvalResult(assign.target)
}
is BinaryExpression -> {
// TODO optimize common cases
translateExpression(assign.value as BinaryExpression)
assignFromEvalResult(assign.target)
}
is ArrayIndexedExpression -> {
translateExpression(assign.value as ArrayIndexedExpression)
// TODO optimize common cases
val arrayExpr = assign.value as ArrayIndexedExpression
val arrayDt = arrayExpr.identifier.targetVarDecl(program.namespace)!!.datatype
val index = arrayExpr.arrayspec.index
if(index is NumericLiteralValue) {
// constant array index value
val arrayVarName = asmIdentifierName(arrayExpr.identifier)
val indexValue = index.number.toInt() * ArrayElementTypes.getValue(arrayDt).memorySize()
when (arrayDt) {
DataType.STR, DataType.STR_S, DataType.ARRAY_UB, DataType.ARRAY_B ->
out(" lda $arrayVarName+$indexValue | sta $ESTACK_LO_HEX,x | dex")
DataType.ARRAY_UW, DataType.ARRAY_W ->
out(" lda $arrayVarName+$indexValue | sta $ESTACK_LO_HEX,x | lda $arrayVarName+$indexValue+1 | sta $ESTACK_HI_HEX,x | dex")
DataType.ARRAY_F ->
out(" lda #<$arrayVarName+$indexValue | ldy #>$arrayVarName+$indexValue | jsr c64flt.push_float")
else ->
throw AssemblyError("weird array type")
}
} else {
translateCalcArrayIndexIntoA(arrayExpr)
readAndPushArrayvalueWithIndexA(arrayDt, arrayExpr.identifier)
}
assignFromEvalResult(assign.target)
}
is TypecastExpression -> {
@ -1561,41 +1587,25 @@ $endLabel""")
}
}
private fun translateExpression(expr: ArrayIndexedExpression) {
private fun translateCalcArrayIndexIntoA(expr: ArrayIndexedExpression) {
val arrayDt = expr.identifier.targetVarDecl(program.namespace)!!.datatype
val sourceName = asmIdentifierName(expr.identifier)
val index = expr.arrayspec.index
when (index) {
is NumericLiteralValue -> {
val indexValue = index.number.toInt() * ArrayElementTypes.getValue(arrayDt).memorySize()
when (arrayDt) {
DataType.STR, DataType.STR_S, DataType.ARRAY_UB, DataType.ARRAY_B ->
out(" lda $sourceName+$indexValue | sta $ESTACK_LO_HEX,x | dex")
DataType.ARRAY_UW, DataType.ARRAY_W ->
out(" lda $sourceName+$indexValue | sta $ESTACK_LO_HEX,x | lda $sourceName+$indexValue+1 | sta $ESTACK_HI_HEX,x | dex")
DataType.ARRAY_F ->
out(" lda #<$sourceName+$indexValue | ldy #>$sourceName+$indexValue | jsr c64flt.push_float")
else ->
throw AssemblyError("weird array type")
}
}
is NumericLiteralValue -> throw AssemblyError("this should be optimized directly")
is RegisterExpr -> {
when (index.register) {
Register.A -> {}
Register.X -> out(" txa")
Register.Y -> out(" tya")
}
readAndPushArrayvalueWithIndexA(arrayDt, sourceName)
}
is IdentifierReference -> {
val indexName = asmIdentifierName(index)
out(" lda $indexName")
readAndPushArrayvalueWithIndexA(arrayDt, sourceName)
}
else -> {
translateExpression(index)
out(" inx | lda $ESTACK_LO_HEX,x")
readAndPushArrayvalueWithIndexA(arrayDt, sourceName)
}
}
}
@ -1659,7 +1669,12 @@ $endLabel""")
when(expression) {
is PrefixExpression -> translateExpression(expression)
is BinaryExpression -> translateExpression(expression)
is ArrayIndexedExpression -> translateExpression(expression)
is ArrayIndexedExpression -> {
// assume *reading* from an array
translateCalcArrayIndexIntoA(expression)
val arrayDt = expression.identifier.targetVarDecl(program.namespace)!!.datatype
readAndPushArrayvalueWithIndexA(arrayDt, expression.identifier)
}
is TypecastExpression -> translateExpression(expression)
is AddressOf -> translateExpression(expression)
is DirectMemoryRead -> translateExpression(expression)
@ -1954,7 +1969,20 @@ $endLabel""")
storeRegisterInMemoryAddress(Register.Y, target.memoryAddress)
}
target.arrayindexed!=null -> {
TODO("put result in arrayindexed $target")
val targetDt = target.arrayindexed!!.inferType(program)!!
val arrayVarName = asmIdentifierName(target.arrayindexed!!.identifier)
when(targetDt) {
in ByteDatatypes -> {
TODO("pop byte into array ${target.arrayindexed}")
}
in WordDatatypes -> {
TODO("pop word into array ${target.arrayindexed}")
}
DataType.FLOAT -> {
TODO("pop float into array ${target.arrayindexed}")
}
else -> throw AssemblyError("weird datatype")
}
}
else -> throw AssemblyError("weird assignment target $target")
}
@ -2043,9 +2071,6 @@ $endLabel""")
sta $targetName+4
""")
}
target.memoryAddress!=null -> {
TODO("assign floatvar $sourceName to memory ${target.memoryAddress}")
}
targetArrayIdx!=null -> {
val index = targetArrayIdx.arrayspec.index
val targetName = asmIdentifierName(targetArrayIdx.identifier)
@ -2256,7 +2281,16 @@ $endLabel""")
targetArrayIdx!=null -> {
val index = targetArrayIdx.arrayspec.index
val targetName = asmIdentifierName(targetArrayIdx.identifier)
TODO("assign word $word to array $targetName [ $index ]")
// TODO optimize common cases
translateExpression(index)
out("""
inx
ldy $ESTACK_LO_HEX,x
lda #<${word.toHex()}
sta $targetName,y
lda #>${word.toHex()}
sta $targetName+1,y
""")
}
else -> TODO("assign word $word to $target")
}
@ -2280,7 +2314,14 @@ $endLabel""")
targetArrayIdx!=null -> {
val index = targetArrayIdx.arrayspec.index
val targetName = asmIdentifierName(targetArrayIdx.identifier)
TODO("assign byte $byte to array $targetName [ $index ]")
// TODO optimize common cases
translateExpression(index)
out("""
inx
ldy $ESTACK_LO_HEX,x
lda #${byte.toHex()}
sta $targetName,y
""")
}
else -> TODO("assign byte $byte to $target")
}
@ -2303,9 +2344,6 @@ $endLabel""")
sta $targetName+4
""")
}
target.memoryAddress!=null -> {
TODO("assign float 0.0 to memory ${target.memoryAddress}")
}
targetArrayIdx!=null -> {
val index = targetArrayIdx.arrayspec.index
val targetName = asmIdentifierName(targetArrayIdx.identifier)
@ -2316,26 +2354,80 @@ $endLabel""")
} else {
// non-zero value
val constFloat = getFloatConst(float)
if (targetIdent != null) {
val targetName = asmIdentifierName(targetIdent)
out("""
lda $constFloat
sta $targetName
lda $constFloat+1
sta $targetName+1
lda $constFloat+2
sta $targetName+2
lda $constFloat+3
sta $targetName+3
lda $constFloat+4
sta $targetName+4
""")
} else {
TODO("assign float $float ($constFloat) to $target")
when {
targetIdent != null -> {
val targetName = asmIdentifierName(targetIdent)
out("""
lda $constFloat
sta $targetName
lda $constFloat+1
sta $targetName+1
lda $constFloat+2
sta $targetName+2
lda $constFloat+3
sta $targetName+3
lda $constFloat+4
sta $targetName+4
""")
}
targetArrayIdx!=null -> {
val index = targetArrayIdx.arrayspec.index
val arrayVarName = asmIdentifierName(targetArrayIdx.identifier)
if(index is NumericLiteralValue) {
val indexValue = index.number.toInt() * MachineDefinition.Mflpt5.MemorySize
out(" lda #<$arrayVarName+$indexValue | ldy #>$arrayVarName+$indexValue | jsr c64flt.pop_float")
} else {
translateCalcArrayIndexIntoA(targetArrayIdx)
out(" sta ${C64Zeropage.SCRATCH_REG} | asl a | asl a | clc | adc ${C64Zeropage.SCRATCH_REG}")
out("""
tay
lda $constFloat
sta $arrayVarName,y
lda $constFloat+1
iny
sta $arrayVarName,y
lda $constFloat+2
iny
sta $arrayVarName,y
lda $constFloat+3
iny
sta $arrayVarName,y
lda $constFloat+4
iny
sta $arrayVarName,y
""") // TODO use a subroutine for this
}
}
else -> TODO("assign float $float to $target")
}
}
}
private fun popAndWriteArrayvalueWithIndexA(arrayDt: DataType, variablename: String) {
when (ArrayElementTypes.getValue(arrayDt).memorySize()) {
1 -> {}
2 -> out(" asl a")
5 -> out(" sta ${C64Zeropage.SCRATCH_REG} | asl a | asl a | clc | adc ${C64Zeropage.SCRATCH_REG}")
else -> throw AssemblyError("invalid memory size")
}
when (arrayDt) {
DataType.STR, DataType.STR_S, DataType.ARRAY_UB, DataType.ARRAY_B ->
out(" tay | inx | lda $ESTACK_LO_HEX,x | sta $variablename,y")
DataType.ARRAY_UW, DataType.ARRAY_W ->
out(" tay | inx | lda $ESTACK_LO_HEX,x | sta $variablename,y | lda $ESTACK_HI_HEX,x | sta $variablename+1,y")
DataType.ARRAY_F ->
out("""
sta $ESTACK_LO_HEX,x
dex
lda #<$variablename
ldy #>$variablename
jsr c64flt.pop_float_to_indexed_var
""")
else ->
throw AssemblyError("weird array type")
}
}
private fun assignFromMemoryByte(target: AssignTarget, address: Int?, identifier: IdentifierReference?) {
val targetIdent = target.identifier
val targetArrayIdx = target.arrayindexed

View File

@ -4,17 +4,16 @@ import prog8.ast.IFunctionCall
import prog8.ast.Program
import prog8.ast.base.ByteDatatypes
import prog8.ast.base.DataType
import prog8.ast.base.Register
import prog8.ast.base.WordDatatypes
import prog8.ast.expressions.Expression
import prog8.ast.expressions.FunctionCall
import prog8.ast.expressions.IdentifierReference
import prog8.ast.expressions.NumericLiteralValue
import prog8.ast.expressions.*
import prog8.ast.statements.FunctionCallStatement
import prog8.compiler.CompilationOptions
import prog8.compiler.Zeropage
import prog8.compiler.target.c64.MachineDefinition.ESTACK_HI_PLUS1_HEX
import prog8.compiler.target.c64.MachineDefinition.ESTACK_LO_HEX
import prog8.compiler.target.c64.MachineDefinition.ESTACK_LO_PLUS1_HEX
import prog8.compiler.toHex
import prog8.functions.FunctionSignature
internal class BuiltinFunctionsAsmGen(private val program: Program,
@ -76,6 +75,154 @@ internal class BuiltinFunctionsAsmGen(private val program: Program,
translateFunctionArguments(fcall.arglist)
asmgen.out(" jsr c64flt.func_$functionName")
}
/*
TODO this was the old code for bit rotations:
Opcode.SHL_BYTE -> AsmFragment(" asl $variable+$index", 8)
Opcode.SHR_UBYTE -> AsmFragment(" lsr $variable+$index", 8)
Opcode.SHR_SBYTE -> AsmFragment(" lda $variable+$index | asl a | ror $variable+$index")
Opcode.SHL_WORD -> AsmFragment(" asl $variable+${index * 2 + 1} | rol $variable+${index * 2}", 8)
Opcode.SHR_UWORD -> AsmFragment(" lsr $variable+${index * 2 + 1} | ror $variable+${index * 2}", 8)
Opcode.SHR_SWORD -> AsmFragment(" lda $variable+${index * 2 + 1} | asl a | ror $variable+${index * 2 + 1} | ror $variable+${index * 2}", 8)
Opcode.ROL_BYTE -> AsmFragment(" rol $variable+$index", 8)
Opcode.ROR_BYTE -> AsmFragment(" ror $variable+$index", 8)
Opcode.ROL_WORD -> AsmFragment(" rol $variable+${index * 2 + 1} | rol $variable+${index * 2}", 8)
Opcode.ROR_WORD -> AsmFragment(" ror $variable+${index * 2 + 1} | ror $variable+${index * 2}", 8)
Opcode.ROL2_BYTE -> AsmFragment(" lda $variable+$index | cmp #\$80 | rol $variable+$index", 8)
Opcode.ROR2_BYTE -> AsmFragment(" lda $variable+$index | lsr a | bcc + | ora #\$80 |+ | sta $variable+$index", 10)
Opcode.ROL2_WORD -> AsmFragment(" asl $variable+${index * 2 + 1} | rol $variable+${index * 2} | bcc + | inc $variable+${index * 2 + 1} |+", 20)
Opcode.ROR2_WORD -> AsmFragment(" lsr $variable+${index * 2 + 1} | ror $variable+${index * 2} | bcc + | lda $variable+${index * 2 + 1} | ora #\$80 | sta $variable+${index * 2 + 1} |+", 30)
*/
"lsl" -> {
// in-place
val what = fcall.arglist.single()
val dt = what.inferType(program)!!
when(dt) {
in ByteDatatypes -> {
when(what) {
is RegisterExpr -> {
when(what.register) {
Register.A -> asmgen.out(" asl a")
Register.X -> asmgen.out(" txa | asl a | tax")
Register.Y -> asmgen.out(" tya | asl a | tay")
}
}
is IdentifierReference -> asmgen.out(" asl ${asmgen.asmIdentifierName(what)}")
is DirectMemoryRead -> {
if(what.addressExpression is NumericLiteralValue) {
asmgen.out(" asl ${(what.addressExpression as NumericLiteralValue).number.toHex()}")
} else {
TODO("lsl memory byte $what")
}
}
is ArrayIndexedExpression -> {
TODO("lsl byte array $what")
}
else -> throw AssemblyError("weird type")
}
}
in WordDatatypes -> {
TODO("lsl word $what")
}
else -> throw AssemblyError("weird type")
}
}
"lsr" -> {
// in-place
val what = fcall.arglist.single()
val dt = what.inferType(program)!!
when(dt) {
DataType.UBYTE -> {
when(what) {
is RegisterExpr -> {
when(what.register) {
Register.A -> asmgen.out(" lsr a")
Register.X -> asmgen.out(" txa | lsr a | tax")
Register.Y -> asmgen.out(" tya | lsr a | tay")
}
}
is IdentifierReference -> asmgen.out(" lsr ${asmgen.asmIdentifierName(what)}")
is DirectMemoryRead -> {
if(what.addressExpression is NumericLiteralValue) {
asmgen.out(" lsr ${(what.addressExpression as NumericLiteralValue).number.toHex()}")
} else {
TODO("lsr memory byte $what")
}
}
is ArrayIndexedExpression -> {
TODO("lsr byte array $what")
}
else -> throw AssemblyError("weird type")
}
}
DataType.BYTE -> {
TODO("lsr sbyte $what")
}
DataType.UWORD -> {
TODO("lsr sword $what")
}
DataType.WORD -> {
TODO("lsr word $what")
}
else -> throw AssemblyError("weird type")
}
}
"rol" -> {
// in-place
val what = fcall.arglist.single()
val dt = what.inferType(program)!!
when(dt) {
DataType.UBYTE -> {
TODO("rol ubyte")
}
DataType.UWORD -> {
TODO("rol uword")
}
else -> throw AssemblyError("weird type")
}
}
"rol2" -> {
// in-place
val what = fcall.arglist.single()
val dt = what.inferType(program)!!
when(dt) {
DataType.UBYTE -> {
TODO("rol2 ubyte")
}
DataType.UWORD -> {
TODO("rol2 uword")
}
else -> throw AssemblyError("weird type")
}
}
"ror" -> {
// in-place
val what = fcall.arglist.single()
val dt = what.inferType(program)!!
when(dt) {
DataType.UBYTE -> {
TODO("ror ubyte")
}
DataType.UWORD -> {
TODO("ror uword")
}
else -> throw AssemblyError("weird type")
}
}
"ror2" -> {
// in-place
val what = fcall.arglist.single()
val dt = what.inferType(program)!!
when(dt) {
DataType.UBYTE -> {
TODO("ror2 ubyte")
}
DataType.UWORD -> {
TODO("ror2 uword")
}
else -> throw AssemblyError("weird type")
}
}
else -> {
translateFunctionArguments(fcall.arglist)
asmgen.out(" jsr prog8_lib.func_$functionName")

View File

@ -127,12 +127,20 @@ The address must be >= ``$0200`` (because ``$00``--``$ff`` is the ZP and ``$100`
to them by their 'short' name directly. If the symbol is not found in the same scope,
the enclosing scope is searched for it, and so on, until the symbol is found.
Scopes are created using several statements:
Scopes are created using either of these two statements:
- blocks (top-level named scope)
- subroutines (nested named scopes)
- for, while, repeat loops (anonymous scope)
- if statements and branching conditionals (anonymous scope)
- subroutines (nested named scope)
.. note::
In contrast to many other programming languages, a new scope is *not* created inside
for, while and repeat statements, nor for the if statement and branching conditionals.
This is a bit restrictive because you have to think harder about what variables you
want to use inside a subroutine. But it is done precisely for this reason; memory in the
target system is very limited and it would be a waste to allocate a lot of variables.
Right now the prog8 compiler is not advanced enough to be able to 'share' or 'overlap'
variables intelligently by itself. So for now, it's something the programmer has to think about.
Program Start and Entry Point
@ -400,7 +408,9 @@ You can also create loops by using the ``goto`` statement, but this should usual
The value of the loop variable or register after executing the loop *is undefined*. Don't use it immediately
after the loop without first assigning a new value to it!
(this is an optimization issue to avoid having to deal with mostly useless post-loop logic to adjust the loop variable's value)
Loop variables that are declared inline are scoped in the loop body so they're not accessible at all after the loop finishes.
Loop variables that are declared inline are not different to them being
defined in a separate var declaration in the subroutine, it's just a readability convenience.
(this may change in the future if the compiler gets more advanced with additional sub-scopes)
Conditional Execution

View File

@ -66,23 +66,28 @@ main {
; plot the points of the 3d cube
; first the points on the back, then the points on the front (painter algorithm)
ubyte i
float rz
float persp
ubyte sx
ubyte sy
for ubyte i in 0 to len(xcoor)-1 {
float rz = rotatedz[i]
for i in 0 to len(xcoor)-1 {
rz = rotatedz[i]
if rz >= 0.1 {
float persp = (5.0+rz)/height
ubyte sx = rotatedx[i] / persp + width/2.0 as ubyte
ubyte sy = rotatedy[i] / persp + height/2.0 as ubyte
persp = (5.0+rz)/height
sx = rotatedx[i] / persp + width/2.0 as ubyte
sy = rotatedy[i] / persp + height/2.0 as ubyte
c64scr.setcc(sx, sy, 46, i+2)
}
}
for ubyte i in 0 to len(xcoor)-1 {
float rz = rotatedz[i]
for i in 0 to len(xcoor)-1 {
rz = rotatedz[i]
if rz < 0.1 {
float persp = (5.0+rz)/height
ubyte sx = rotatedx[i] / persp + width/2.0 as ubyte
ubyte sy = rotatedy[i] / persp + height/2.0 as ubyte
persp = (5.0+rz)/height
sx = rotatedx[i] / persp + width/2.0 as ubyte
sy = rotatedy[i] / persp + height/2.0 as ubyte
c64scr.setcc(sx, sy, 81, i+2)
}
}

View File

@ -1,25 +1,42 @@
%import c64lib
%import c64utils
%import c64flt
%zeropage basicsafe
%option enable_floats
main {
ubyte[10] barray
uword[10] warray
float[10] farray
&ubyte memubarray = 1000
&uword memuwarray = 1000
&float memfltarray = 1000
sub start() {
delay1(1)
delay2(1)
delay3(1)
ubyte i
uword uw
float fl = farray[2]
sub delay1(ubyte note1) {
A= note1
}
sub delay2(ubyte note1) {
A= note1
}
sub delay3(ubyte note1) {
A= note1
}
barray[4] = 4
barray[i] = 4
barray[i+4] = 4
memubarray[4] = 4
memubarray[i] = 4
memubarray[i+4] = 4
warray[4] = 4
warray[i] = 4
warray[i+4] = 4
memuwarray[4] = 4
memuwarray[i] = 4
memuwarray[i+4] = 4
farray[4] = 4
farray[i] = 4
farray[i+4] = 4
memfltarray[4] = 4
memfltarray[i] = 4
memfltarray[i+4] = 4
}
}