implemented the arithmetic functions with new cc. fixed sgn().

This commit is contained in:
Irmen de Jong 2020-11-04 00:21:53 +01:00
parent 0edd50e956
commit 9d17421c66
7 changed files with 205 additions and 198 deletions

View File

@ -96,7 +96,7 @@ stack_uw2float .proc
.pend .pend
stack_float2w .proc ; also used for float2b stack_float2w .proc ; also used for float2b
jsr pop_float_fac1 jsr MOVFM
stx P8ZP_SCRATCH_REG stx P8ZP_SCRATCH_REG
jsr AYINT jsr AYINT
ldx P8ZP_SCRATCH_REG ldx P8ZP_SCRATCH_REG
@ -109,7 +109,7 @@ stack_float2w .proc ; also used for float2b
.pend .pend
stack_float2uw .proc ; also used for float2ub stack_float2uw .proc ; also used for float2ub
jsr pop_float_fac1 jsr MOVFM
stx P8ZP_SCRATCH_REG stx P8ZP_SCRATCH_REG
jsr GETADR jsr GETADR
ldx P8ZP_SCRATCH_REG ldx P8ZP_SCRATCH_REG
@ -173,6 +173,7 @@ pop_float .proc
.pend .pend
pop_float_fac1 .proc pop_float_fac1 .proc
; TODO REMOVE THIS?? But is used in code generation at various places still
; -- pops float from stack into FAC1 ; -- pops float from stack into FAC1
lda #<fmath_float1 lda #<fmath_float1
ldy #>fmath_float1 ldy #>fmath_float1
@ -471,7 +472,7 @@ func_sin_into_fac1 .proc
.pend .pend
func_cos_into_fac1 .proc func_cos_into_fac1 .proc
jsr pop_float_fac1 jsr MOVFM
stx P8ZP_SCRATCH_REG stx P8ZP_SCRATCH_REG
jsr COS jsr COS
ldx P8ZP_SCRATCH_REG ldx P8ZP_SCRATCH_REG
@ -479,7 +480,7 @@ func_cos_into_fac1 .proc
.pend .pend
func_tan_into_fac1 .proc func_tan_into_fac1 .proc
jsr pop_float_fac1 jsr MOVFM
stx P8ZP_SCRATCH_REG stx P8ZP_SCRATCH_REG
jsr TAN jsr TAN
ldx P8ZP_SCRATCH_REG ldx P8ZP_SCRATCH_REG
@ -487,7 +488,7 @@ func_tan_into_fac1 .proc
.pend .pend
func_atan_into_fac1 .proc func_atan_into_fac1 .proc
jsr pop_float_fac1 jsr MOVFM
stx P8ZP_SCRATCH_REG stx P8ZP_SCRATCH_REG
jsr ATN jsr ATN
ldx P8ZP_SCRATCH_REG ldx P8ZP_SCRATCH_REG
@ -495,7 +496,7 @@ func_atan_into_fac1 .proc
.pend .pend
func_ln_into_fac1 .proc func_ln_into_fac1 .proc
jsr pop_float_fac1 jsr MOVFM
stx P8ZP_SCRATCH_REG stx P8ZP_SCRATCH_REG
jsr LOG jsr LOG
ldx P8ZP_SCRATCH_REG ldx P8ZP_SCRATCH_REG
@ -503,12 +504,12 @@ func_ln_into_fac1 .proc
.pend .pend
func_log2_into_fac1 .proc func_log2_into_fac1 .proc
jsr pop_float_fac1 jsr MOVFM
stx P8ZP_SCRATCH_REG stx P8ZP_SCRATCH_REG
jsr LOG jsr LOG
jsr MOVEF jsr MOVEF
lda #<c64.FL_LOG2 lda #<FL_LOG2
ldy #>c64.FL_LOG2 ldy #>FL_LOG2
jsr MOVFM jsr MOVFM
jsr FDIVT jsr FDIVT
ldx P8ZP_SCRATCH_REG ldx P8ZP_SCRATCH_REG
@ -516,7 +517,7 @@ func_log2_into_fac1 .proc
.pend .pend
func_sqrt_into_fac1 .proc func_sqrt_into_fac1 .proc
jsr pop_float_fac1 jsr MOVFM
stx P8ZP_SCRATCH_REG stx P8ZP_SCRATCH_REG
jsr SQR jsr SQR
ldx P8ZP_SCRATCH_REG ldx P8ZP_SCRATCH_REG
@ -525,7 +526,7 @@ func_sqrt_into_fac1 .proc
func_rad_into_fac1 .proc func_rad_into_fac1 .proc
; -- convert degrees to radians (d * pi / 180) ; -- convert degrees to radians (d * pi / 180)
jsr pop_float_fac1 jsr MOVFM
stx P8ZP_SCRATCH_REG stx P8ZP_SCRATCH_REG
lda #<_pi_div_180 lda #<_pi_div_180
ldy #>_pi_div_180 ldy #>_pi_div_180
@ -537,7 +538,7 @@ _pi_div_180 .byte 123, 14, 250, 53, 18 ; pi / 180
func_deg_into_fac1 .proc func_deg_into_fac1 .proc
; -- convert radians to degrees (d * (1/ pi * 180)) ; -- convert radians to degrees (d * (1/ pi * 180))
jsr pop_float_fac1 jsr MOVFM
stx P8ZP_SCRATCH_REG stx P8ZP_SCRATCH_REG
lda #<_one_over_pi_div_180 lda #<_one_over_pi_div_180
ldy #>_one_over_pi_div_180 ldy #>_one_over_pi_div_180
@ -548,7 +549,7 @@ _one_over_pi_div_180 .byte 134, 101, 46, 224, 211 ; 1 / (pi * 180)
.pend .pend
func_round_into_fac1 .proc func_round_into_fac1 .proc
jsr pop_float_fac1 jsr MOVFM
stx P8ZP_SCRATCH_REG stx P8ZP_SCRATCH_REG
jsr FADDH jsr FADDH
jsr INT jsr INT
@ -557,7 +558,7 @@ func_round_into_fac1 .proc
.pend .pend
func_floor_into_fac1 .proc func_floor_into_fac1 .proc
jsr pop_float_fac1 jsr MOVFM
stx P8ZP_SCRATCH_REG stx P8ZP_SCRATCH_REG
jsr INT jsr INT
ldx P8ZP_SCRATCH_REG ldx P8ZP_SCRATCH_REG
@ -566,7 +567,7 @@ func_floor_into_fac1 .proc
func_ceil_into_fac1 .proc func_ceil_into_fac1 .proc
; -- ceil: tr = int(f); if tr==f -> return else return tr+1 ; -- ceil: tr = int(f); if tr==f -> return else return tr+1
jsr pop_float_fac1 jsr MOVFM
stx P8ZP_SCRATCH_REG stx P8ZP_SCRATCH_REG
ldx #<fmath_float1 ldx #<fmath_float1
ldy #>fmath_float1 ldy #>fmath_float1
@ -707,8 +708,8 @@ func_sum_f_into_fac1 .proc
rts rts
.pend .pend
sign_f .proc sign_f_cc .proc
jsr pop_float_fac1 jsr MOVFM
jsr SIGN jsr SIGN
sta P8ESTACK_LO,x sta P8ESTACK_LO,x
dex dex

View File

@ -1243,83 +1243,75 @@ mul_word_100 .proc
; ----------- end optimized multiplications ----------- ; ----------- end optimized multiplications -----------
sign_b .proc
lda P8ESTACK_LO+1,x
beq _sign_zero
bmi _sign_neg
_sign_pos lda #1
sta P8ESTACK_LO+1,x
rts
_sign_neg lda #-1
_sign_zero sta P8ESTACK_LO+1,x
rts
.pend
sign_ub .proc
lda P8ESTACK_LO+1,x
beq sign_b._sign_zero
bne sign_b._sign_pos
.pend
sign_w .proc
lda P8ESTACK_HI+1,x
bmi sign_b._sign_neg
beq sign_ub
bne sign_b._sign_pos
.pend
sign_uw .proc
lda P8ESTACK_HI+1,x
beq _sign_possibly_zero
_sign_pos lda #1
sta P8ESTACK_LO+1,x
rts
_sign_possibly_zero lda P8ESTACK_LO+1,x
bne _sign_pos
sta P8ESTACK_LO+1,x
rts
.pend
sign_b_into_A .proc
; -- A = sgn(pop stack byte)
inx
lda P8ESTACK_LO,x
beq _sign_zero
bmi _sign_neg
_sign_pos lda #1
rts
_sign_neg lda #-1
_sign_zero rts
.pend
sign_ub_into_A .proc sign_ub_into_A .proc
; -- A = sgn(pop stack ubyte) cmp #0
lda P8ESTACK_LO+1,x bne _pos
bne sign_b._sign_pos rts
_pos lda #1
rts rts
.pend .pend
sign_w_into_A .proc sign_ub_cc .proc
; -- A = sgn(pop stack word) jsr sign_ub_into_A
lda P8ESTACK_HI+1,x sta P8ESTACK_LO,x
bmi sign_b._sign_neg dex
bne sign_b._sign_pos
rts rts
.pend .pend
sign_uw_into_A .proc sign_uw_into_A .proc
; -- A = sgn(pop stack uword) cpy #0
lda P8ESTACK_HI+1,x beq _possibly_zero
beq _sign_possibly_zero _pos lda #1
_sign_pos lda #1
rts rts
_sign_possibly_zero lda P8ESTACK_LO+1,x _possibly_zero cmp #0
bne _sign_pos bne _pos
rts rts
.pend .pend
sign_uw_cc .proc
jsr sign_uw_into_A
sta P8ESTACK_LO,x
dex
rts
.pend
sign_b_into_A .proc
cmp #0
beq _zero
bmi _neg
lda #1
_zero rts
_neg lda #-1
rts
.pend
sign_b_cc .proc
jsr sign_b_into_A
sta P8ESTACK_LO,x
dex
rts
.pend
sign_w_into_A .proc
cpy #0
beq _possibly_zero
bmi _neg
_pos lda #1
rts
_neg lda #-1
rts
_possibly_zero cmp #0
bne _pos
rts
.pend
sign_w_cc .proc
jsr sign_w_into_A
sta P8ESTACK_LO,x
dex
rts
.pend
; bit shifts. ; bit shifts.
; anything below 3 is done inline. anything above 7 is done via other optimizations. ; anything below 3 is done inline. anything above 7 is done via other optimizations.

View File

@ -704,18 +704,11 @@ func_read_flags .proc
.pend .pend
func_sqrt16_into_A .proc func_sqrt16_into_A .proc
jsr func_sqrt16
jmp func_any_b_into_A._popA
.pend
func_sqrt16 .proc
; integer square root from http://6502org.wikidot.com/software-math-sqrt ; integer square root from http://6502org.wikidot.com/software-math-sqrt
txa
pha
lda P8ESTACK_LO+1,x
ldy P8ESTACK_HI+1,x
sta P8ZP_SCRATCH_W1 sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1 sty P8ZP_SCRATCH_W1+1
txa
pha
lda #0 lda #0
sta P8ZP_SCRATCH_B1 sta P8ZP_SCRATCH_B1
sta P8ZP_SCRATCH_REG sta P8ZP_SCRATCH_REG
@ -741,7 +734,6 @@ func_sqrt16 .proc
pla pla
tax tax
lda P8ZP_SCRATCH_B1 lda P8ZP_SCRATCH_B1
sta P8ESTACK_LO+1,x
rts rts
.pend .pend
@ -828,7 +820,7 @@ func_sin8_cc .proc
func_sin8u_cc .proc func_sin8u_cc .proc
tay tay
lda _sinecos8u,y lda func_sin8u_into_A._sinecos8u,y
sta P8ESTACK_LO,x sta P8ESTACK_LO,x
dex dex
rts rts
@ -837,9 +829,10 @@ func_sin8u_cc .proc
func_sin16_cc .proc func_sin16_cc .proc
tay tay
lda func_sin16_into_AY._sinecos8lo,y lda func_sin16_into_AY._sinecos8lo,y
sta P8ESTACK_LO+1,x sta P8ESTACK_LO,x
lda func_sin16_into_AY._sinecos8hi,y lda func_sin16_into_AY._sinecos8hi,y
sta P8ESTACK_HI+1,x sta P8ESTACK_HI,x
dex
rts rts
.pend .pend
@ -847,9 +840,10 @@ func_sin16_cc .proc
func_sin16u_cc .proc func_sin16u_cc .proc
tay tay
lda func_sin16u_into_AY._sinecos8ulo,y lda func_sin16u_into_AY._sinecos8ulo,y
sta P8ESTACK_LO+1,x sta P8ESTACK_LO,x
lda func_sin16u_into_AY._sinecos8uhi,y lda func_sin16u_into_AY._sinecos8uhi,y
sta P8ESTACK_HI+1,x sta P8ESTACK_HI,x
dex
rts rts
.pend .pend
@ -872,18 +866,20 @@ func_cos8u_cc .proc
func_cos16_cc .proc func_cos16_cc .proc
tay tay
lda func_sin16_into_AY._sinecos8lo+64,y lda func_sin16_into_AY._sinecos8lo+64,y
sta P8ESTACK_LO+1,x sta P8ESTACK_LO,x
lda func_sin16_into_AY._sinecos8hi+64,y lda func_sin16_into_AY._sinecos8hi+64,y
sta P8ESTACK_HI+1,x sta P8ESTACK_HI,x
dex
rts rts
.pend .pend
func_cos16u_cc .proc func_cos16u_cc .proc
tay tay
lda func_sin16u_into_AY._sinecos8ulo+64,y lda func_sin16u_into_AY._sinecos8ulo+64,y
sta P8ESTACK_LO+1,x sta P8ESTACK_LO,x
lda func_sin16u_into_AY._sinecos8uhi+64,y lda func_sin16u_into_AY._sinecos8uhi+64,y
sta P8ESTACK_HI+1,x sta P8ESTACK_HI,x
dex
rts rts
.pend .pend

View File

@ -475,11 +475,11 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
val dt = fcall.args.single().inferType(program) val dt = fcall.args.single().inferType(program)
if(resultToStack) { if(resultToStack) {
when (dt.typeOrElse(DataType.STRUCT)) { when (dt.typeOrElse(DataType.STRUCT)) {
DataType.UBYTE -> asmgen.out(" jsr math.sign_ub") DataType.UBYTE -> asmgen.out(" jsr math.sign_ub_cc")
DataType.BYTE -> asmgen.out(" jsr math.sign_b") DataType.BYTE -> asmgen.out(" jsr math.sign_b_cc")
DataType.UWORD -> asmgen.out(" jsr math.sign_uw") DataType.UWORD -> asmgen.out(" jsr math.sign_uw_cc")
DataType.WORD -> asmgen.out(" jsr math.sign_w") DataType.WORD -> asmgen.out(" jsr math.sign_w_cc")
DataType.FLOAT -> asmgen.out(" jsr floats.sign_f") DataType.FLOAT -> asmgen.out(" jsr floats.sign_f_cc")
else -> throw AssemblyError("weird type $dt") else -> throw AssemblyError("weird type $dt")
} }
} else { } else {
@ -1054,6 +1054,29 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
private fun translateArguments(args: MutableList<Expression>, signature: FSignature) { private fun translateArguments(args: MutableList<Expression>, signature: FSignature) {
val callConv = signature.callConvention(args.map { it.inferType(program).typeOrElse(DataType.STRUCT) }) val callConv = signature.callConvention(args.map { it.inferType(program).typeOrElse(DataType.STRUCT) })
fun getSourceForFloat(value: Expression): AsmAssignSource {
return when (value) {
is IdentifierReference -> {
val addr = AddressOf(value, value.position)
AsmAssignSource.fromAstSource(addr, program, asmgen)
}
is NumericLiteralValue -> {
throw AssemblyError("float literals should have been converted into autovar")
}
else -> {
TODO("evaluate float expression, store float in (to be defined) result variable, get address of that variable.")
// val variable = IdentifierReference(listOf("p8_float_eval_result"), value.position)
// variable.linkParents(value)
// val assign = AsmAssignment(AsmAssignSource.fromAstSource(value, program, asmgen),
// AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, DataType.FLOAT, null, variableAsmName = asmgen.asmVariableName(variable)),
// false, Position.DUMMY)
// asmgen.translateNormalAssignment(assign)
// val addr = AddressOf(variable, value.position)
// AsmAssignSource.fromAstSource(addr, program, asmgen)
}
}
}
args.zip(callConv.params).zip(signature.parameters).forEach { args.zip(callConv.params).zip(signature.parameters).forEach {
val paramName = it.second.name val paramName = it.second.name
val conv = it.first.second val conv = it.first.second
@ -1061,24 +1084,32 @@ internal class BuiltinFunctionsAsmGen(private val program: Program, private val
when { when {
conv.variable -> { conv.variable -> {
val varname = "prog8_lib.func_${signature.name}_cc._arg_${paramName}" // TODO after all builtin funcs have been changed into _cc, remove that suffix again val varname = "prog8_lib.func_${signature.name}_cc._arg_${paramName}" // TODO after all builtin funcs have been changed into _cc, remove that suffix again
val src = if(conv.dt==DataType.FLOAT || conv.dt in PassByReferenceDatatypes) { val src = when (conv.dt) {
// put the address of the argument in AY DataType.FLOAT -> getSourceForFloat(value)
val addr = AddressOf(value as IdentifierReference, value.position) in PassByReferenceDatatypes -> {
AsmAssignSource.fromAstSource(addr, program, asmgen) // put the address of the argument in AY
} else { val addr = AddressOf(value as IdentifierReference, value.position)
AsmAssignSource.fromAstSource(value, program, asmgen) AsmAssignSource.fromAstSource(addr, program, asmgen)
}
else -> {
AsmAssignSource.fromAstSource(value, program, asmgen)
}
} }
val tgt = AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, conv.dt, null, variableAsmName = varname) val tgt = AsmAssignTarget(TargetStorageKind.VARIABLE, program, asmgen, conv.dt, null, variableAsmName = varname)
val assign = AsmAssignment(src, tgt, false, value.position) val assign = AsmAssignment(src, tgt, false, value.position)
asmgen.translateNormalAssignment(assign) asmgen.translateNormalAssignment(assign)
} }
conv.reg != null -> { conv.reg != null -> {
val src = if(conv.dt==DataType.FLOAT || conv.dt in PassByReferenceDatatypes) { val src = when (conv.dt) {
// put the address of the argument in AY DataType.FLOAT -> getSourceForFloat(value)
val addr = AddressOf(value as IdentifierReference, value.position) in PassByReferenceDatatypes -> {
AsmAssignSource.fromAstSource(addr, program, asmgen) // put the address of the argument in AY
} else { val addr = AddressOf(value as IdentifierReference, value.position)
AsmAssignSource.fromAstSource(value, program, asmgen) AsmAssignSource.fromAstSource(addr, program, asmgen)
}
else -> {
AsmAssignSource.fromAstSource(value, program, asmgen)
}
} }
val tgt = AsmAssignTarget.fromRegisters(conv.reg, null, program, asmgen) val tgt = AsmAssignTarget.fromRegisters(conv.reg, null, program, asmgen)
val assign = AsmAssignment(src, tgt, false, value.position) val assign = AsmAssignment(src, tgt, false, value.position)

View File

@ -53,6 +53,7 @@ X = BinExpr X = LeftExpr
*/ */
// TODO can be generelized a bit by allowing LEFT EXPR to be more complex
if(binExpr.operator in augmentAssignmentOperators && isSimpleTarget(assignment.target, program.namespace)) { if(binExpr.operator in augmentAssignmentOperators && isSimpleTarget(assignment.target, program.namespace)) {
if(assignment.target isSameAs binExpr.left || assignment.target isSameAs binExpr.right) if(assignment.target isSameAs binExpr.left || assignment.target isSameAs binExpr.right)
return noModifications return noModifications

View File

@ -8,9 +8,6 @@
; Cleanup and porting to C by Ullrich von Bassewitz. ; Cleanup and porting to C by Ullrich von Bassewitz.
; Converted to prog8 by Irmen de Jong. ; Converted to prog8 by Irmen de Jong.
; TODO the random charset is all wrong
; TODO why has the prg become bigger since register args?
main { main {
const uword SCREEN1 = $E000 const uword SCREEN1 = $E000

View File

@ -4,8 +4,20 @@
%zeropage basicsafe %zeropage basicsafe
; builtin functions converted to new call convention: ; builtin functions converted to new call convention:
; abs (int + float) ; abs
; atan
; ceil
; cos (float), cos8, cos8u, cos16, cos16u
; deg
; floor
; ln
; log2
; rad
; round
; sgn (float), sgn (integers)
; sin (float), sin8, sin8u, sin16, sin16u
; sqrt (float), sqrt16
; tan
main { main {
@ -22,107 +34,84 @@ main {
float fzero=0.0 float fzero=0.0
float rr=0.0 float rr=0.0
rr = -4.0 ; TODO byte -> word conversion is wrong
for ubb in 0 to 20 {
floats.print_f(abs(rr)) rr = 2.0
for ubb in 0 to 10 {
floats.print_f(tan(rr))
txt.chrout('\n') txt.chrout('\n')
rr += 0.5 rr += 0.5
} }
txt.chrout('\n') txt.chrout('\n')
txt.chrout('\n') txt.chrout('\n')
rr = -2.0 rr = 2.0
for ubb in 0 to 20 { for ubb in 0 to 10 {
floats.print_f(abs(rr)+fzero) floats.print_f(tan(rr)+fzero)
txt.chrout('\n') txt.chrout('\n')
rr += 0.5 rr += 0.5
} }
txt.chrout('\n') txt.chrout('\n')
txt.chrout('\n') txt.chrout('\n')
for ubb in 0 to 20 { ; for uww in 0 to 50000 step 10000 {
txt.print_ub(abs(ubb)) ; txt.print_ub(sqrt16(uww))
txt.chrout('\n')
}
txt.chrout('\n')
txt.chrout('\n')
for ubb in 0 to 20 {
txt.print_ub(abs(ubb)+zerobb)
txt.chrout('\n')
}
txt.chrout('\n')
txt.chrout('\n')
for bb in -10 to 10 {
txt.print_b(abs(bb))
txt.chrout('\n')
}
txt.chrout('\n')
txt.chrout('\n')
for bb in -10 to 10 {
txt.print_b(abs(bb)+zerobb)
txt.chrout('\n')
}
txt.chrout('\n')
txt.chrout('\n')
for uww in 0 to 20 {
txt.print_uw(abs(uww))
txt.chrout('\n')
}
txt.chrout('\n')
txt.chrout('\n')
for uww in 0 to 20 {
txt.print_uw(abs(uww)+zeroww)
txt.chrout('\n')
}
txt.chrout('\n')
txt.chrout('\n')
for ww in -10 to 10 {
txt.print_w(abs(ww))
txt.chrout('\n')
}
txt.chrout('\n')
txt.chrout('\n')
for ww in -10 to 10 {
txt.print_w(abs(ww)+zeroww)
txt.chrout('\n')
}
txt.chrout('\n')
txt.chrout('\n')
; for ubb in 0 to 20 {
; floats.print_f(sin(rr))
; txt.chrout('\n') ; txt.chrout('\n')
; rr += 0.01
; } ; }
; txt.chrout('\n') ; txt.chrout('\n')
; txt.chrout('\n') ; txt.chrout('\n')
; for ubb in 0 to 20 {
; floats.print_f(cos(rr)) ; for ww in -5 to 5 {
; txt.print_b(sgn(ww)+zerobb)
; txt.chrout('\n') ; txt.chrout('\n')
; rr += 0.01
; } ; }
; txt.chrout('\n') ; txt.chrout('\n')
; txt.chrout('\n') ; txt.chrout('\n')
; for ubb in 0 to 20 {
; floats.print_f(tan(rr)) ; for ww in -2 to 2 {
; txt.print_b(sgn(ww))
; txt.chrout('\n') ; txt.chrout('\n')
; rr += 0.01
; } ; }
; txt.chrout('\n') ; txt.chrout('\n')
; txt.chrout('\n') ; txt.chrout('\n')
; for ubb in 0 to 20 { ;
; floats.print_f(atan(rr)) ; for ww in -2 to 2 {
; txt.print_b(sgn(ww)+zerobb)
; txt.chrout('\n') ; txt.chrout('\n')
; rr += 0.01
; } ; }
; txt.chrout('\n')
; txt.chrout('\n')
;
; for bb in -2 to 2 {
; txt.print_b(sgn(bb))
; txt.chrout('\n')
; }
; txt.chrout('\n')
; txt.chrout('\n')
;
; for bb in -2 to 2 {
; txt.print_b(sgn(bb)+zerobb)
; txt.chrout('\n')
; }
; txt.chrout('\n')
; txt.chrout('\n')
; for bb in -5 to 5 {
; txt.print_b(sgn(bb))
; txt.chrout('\n')
; }
; txt.chrout('\n')
; txt.chrout('\n')
;
; for bb in -5 to 5 {
; txt.print_b(sgn(bb)+zerobb)
; txt.chrout('\n')
; }
; txt.chrout('\n')
; txt.chrout('\n')
;
testX() testX()